C# 中的IOCP线程池


原文地址:http://www.theukwebdesigncompany.com/articles/iocp-thread-pooling.php

PartOne : Introduction

当使用C#构建服务器端应用时,创建线程池是一个十分重要的能力。线程池允许服务器端程序通过队列最大程度的处理任务。除了构建线程池之外,还有两个方案:

1.        使用单线程处理所有的任务。

2.        当任务需要时就产生子线程来处理任务。

本文定义任务为需要处理的事件,这些工作也许是也许不是分布式的数据。目标是以最高的效率和最短的时间处理这些任务。

       首先是一个通用的原则,如果可以用单线程处理所有任务,那么使用单线程。如果同时使用多线程处理任务是不必要的,意味着应用程序有更多的事情要做,或者单线程处理更快。比如当多个线程请求同一资源时,会产生阻塞,必须等待前面的线程处理完之后才可以获取资源,完成任务处理。在发生阻塞时,等待的线程会进入休眠状态,不做任何工作。但是实际上这些线程会对操作系统产生很大的负担。操作系统必须监控任务处理情况,当资源释放时,决定唤醒哪个线程进行处理。如果需要处理任务的线程因为等待资源而处于休眠状态,这样我们就需要处理这个任务。在这种情况下可以将这些线程放入队列,并用单个线程处理这个队列。

       最先等待资源的线程不一定先得到资源,如图-1所示。

      

图-1 线程示例图

       如果任务之间是相互独立的,这儿的相互独立是指不会发生资源冲突,在处理多任务时可以产生多个线程来处理不同的任务。此时的问题是操作系统,比如windows操作系统,运行多个线程时,需要等待CPU。Windosw操作系统需要管理所有的线程,而UNIX操作系统则不需要。如果有大量线程同时运行,系统性能将会大大降低。

       在.net框架,“system.Threading”命名空间内有一个ThreadPool类。不幸的是这个类是一个静态类,只能有一个线程池。这个线程池不允许设定线程的并发级别。不同的并发级别允许并发的线程不同。如果我们设置合适的并发级别,我们会得到最高的效率。

       假设我们有一个可以允许4个线程并发级别为1的线程池。然后有三个任务发送给线程池处理。只能有一个线程处理任务,其他的线程都处在等待状态。如图-2。


图-2 线程池

       那么当并发级别设置为1时,如果运行多个线程?如果图-2 中的线程1 进行休眠,线程池将会启动另外一个线程。如图-3。


图-3

       突然的线程1 被唤醒,线程4很有可能还没有结束。这样我们就有了两个线程同时运行,虽然并发级别仍然为1.如图-4。

      

图-4

       其他的线程只有等这两个线程都进入休眠状态才能运行。即使并发级别限制活动线程池中在任意给定时间的数量,我们可以有更多的活动线程然后并发级别允许。这一切都取决于池中的线程的状态,以及如何快速的线程可以完成,他们正在处理的工作。

       一个好的设置并发级别的策略是按照系统的CPU的数量进行设置。如果CPU处在空闲状态,此时有任务需要处理,则启动一个新的线程来处理任务。如果CPU忙,则不会新建线程。同时我们需要注意,不要让一个线程长时间的处于休眠状态,这会导致所有的线程池都处在激活状态,影响线程池的效率和服务器的效率。

       下面会介绍如何添加 IOCP线程池到应用中。

Part2: Defining the Solution

       略。

转载于:https://www.cnblogs.com/andy-2014/p/4964246.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最近有项目要做一个高性能网络服务器,去网络上搜到到的都是C++版本而且是英文或者简单的DEMO,所以自己动手写了C# 的DEMO。 网络上只写接收到的数据,没有说怎么处理缓冲区数据,本DEMO简单的介绍如何处理接收到的数据。简单易用,希望对大家有用. 1、在C#,不用去面对完成端口的操作系统内核对象,Microsoft已经为我们提供了SocketAsyncEventArgs类,它封装了IOCP的使用。请参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socketasynceventargs.aspx?cs-save-lang=1&cs-lang=cpp#code-snippet-1。 2、我的SocketAsyncEventArgsPool类使用List对象来存储对客户端来通信的SocketAsyncEventArgs对象,它相当于直接使用内核对象时的IoContext。我这样设计比用堆栈来实现的好处理是,我可以在SocketAsyncEventArgsPool池找到任何一个与服务器连接的客户,主动向它发信息。而用堆栈来实现的话,要主动给客户发信息,则还要设计一个结构来存储已连接上服务器的客户。 3、对每一个客户端不管还发送还是接收,我使用同一个SocketAsyncEventArgs对象,对每一个客户端来说,通信是同步进行的,也就是说服务器高度保证同一个客户连接上要么在投递发送请求,并等待;或者是在投递接收请求,等待。本例只做echo服务器,还未考虑由服务器主动向客户发送信息。 4、SocketAsyncEventArgs的UserToken被直接设定为被接受的客户端Socket。 5、没有使用BufferManager 类,因为我在初始化时给每一个SocketAsyncEventArgsPool的对象分配一个缓冲区,发送时使用Arrary.Copy来进行字符拷贝,不去改变缓冲区的位置,只改变使用的长度,因此在下次投递接收请求时恢复缓冲区长度就可以了!如果要主动给客户发信息的话,可以new一个SocketAsyncEventArgs对象,或者在初始化建立几个来专门用于主动发送信息,因为这种需求一般是进行信息群发,建立一个对象可以用于很多次信息发送,总体来看,这种花销不大,还减去了字符拷贝和消耗。 6、测试结果:(在我的笔记本上时行的,我的本本是T420 I7 8G内存) 100客户 100,000(十万次)不间断的发送接收数据(发送和接收之间没有Sleep,就一个一循环,不断的发送与接收) 耗时3004.6325 秒完成 总共 10,000,000 一千万次访问 平均每分完成 199,691.6 次发送与接收 平均每秒完成 3,328.2 次发送与接收 整个运行过程,内存消耗在开始两三分种后就保持稳定不再增涨。 看了一下对每个客户端的延迟最多不超过2秒。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值