dot net线程池ThreadPool.doc_第1页
dot net线程池ThreadPool.doc_第2页
dot net线程池ThreadPool.doc_第3页
dot net线程池ThreadPool.doc_第4页
dot net线程池ThreadPool.doc_第5页
已阅读5页,还剩2页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

dot net线程池ThreadPool一、线程池的适用范围在日常使用多线程开发的时候,一般都构造一个Thread示例,然后调用Start使之执行。如果一个线程它大部分时间花费在等待某个事件响应 的发生然后才予以响应;或者如果在一定期间内重复性地大量创建线程。这些时候个人感觉利用线程池(ThreadPool)会比单纯创建线程 (Thread)要好。这是由于线程池能在需要的时候把空闲的线程提取出来使用,在线程使用完毕的时候对线程回收达到对象复用的效果。这个就涉及到池的性 质了。线程(Thread)很容易跟数据库连接、流、Socket套接字这部分非托管资源归在一起,但是个人认为Thread并不是非托管资源,有个低级 点的判别办法,就是Thread没有去实现IDispose接口,利用Reflector打开去查看的话,里面就有一个析构函数Thread()它实际 上是调用了一个外部方法InternalFinalize(),估计这个就涉及到CLR里面的东西了。如果频繁开启线程,对资源的消耗会比用线程池的要 多。二、线程池的容量和对象管理既然上面提及到池的性质,在TheardPool这个线程池中也可以看到一个对象池的特点,这个可以在日后我们创建对象池时可以作为参考。虽然 本人以前也写过一个Socket的对象池,但是运行起来的性能不好。CLR内部其实拥有一个数据库连接的对象池,实现的效果跟ThreadPool类似,能让对象复用。在以前定义Socket池时只定义了一个对象上限,没有下限的概念;在ThreadPool中,池内对象的上下限都可以进行设置和获取1 public static bool SetMinThreads(int workerThreads, int completionPortThreads);2 public static bool SetMaxThreads(int workerThreads, int completionPortThreads);3 4 public static void GetMaxThreads(out int workerThreads, out int completionPortThreads);5 public static void GetMinThreads(out int workerThreads, out int completionPortThreads);至于这里有两种线程的原因迟点再提。MinThread指的是线程池初始或者空闲时保留最少的线程数,这个值与CLR的版本和CPU的核心数有关系。在CLR SP1之前的版本中,线程池默认最大线程数是 处理器数 * 25,在CLR SP1之后默认最大线程数是处理器数 * 250。最少线程数则是 处理器数,于是我也尝试了一下。不过这里又涉及到CLR与.NET Framework的关系。.NET Framework | CLR-2.0 RTM | 2.0.50727.42 2.0 SP1 | 2.0.50727.1433 2.0 SP2 | 2.0.50727.3053 3.0 RTM | 2.0 RTM 3.0 SP1| 2.0 SP1 3.0 SP2| 2.0 SP2 3.5 RTM | 2.0 SP1 3.5 SP1 | 2.0 SP2 4.0 RTM | 4.0.30319.1 我自己通过 Environment类的Version属性获取CLR的版本号。下面这段代码,我使用几个版本的.NET Framework去编译 。 int i1,i2; ThreadPool.GetMaxThreads(out i1, out i2); Console.WriteLine(Max workerThreads :+ i1+ completionPortThreads:+i2); ThreadPool.GetMinThreads(out i1,out i2); Console.WriteLine(Min workerThreads:+i1 + completionPortThreads: + i2); Console.WriteLine( CLR Version: 0 , Environment.Version);得出的结果有点失望,失望的不是与上面说的相违背。而是我这里用的.NET Framework不全。2.0和3.5的CLR都是SP2本版本的3.5的结果如下2.0的结果如下从上面的结果看出最大线程数和最小线程数符合。还是得说一下我用的是i5处理器,双核四线程。下面这个我是在虚拟机上跑的,单核的虚拟机用的是.NET Framework1.0的,CLR也是1.0的。的确最少线程数和最多工作线程数是对得上的,但是IO线程数还是保留着1000个。最后看看上跑熟悉的.NET 4.0的我在虚拟机和本机上分别跑过,IO线程还是一样1000没变,估计前面的公式对它不适用,但工作数还是有点怪怪的,单核的就1023条,但是在i5上的却不是1024的倍数。使用了线程池这个对象,给人的感觉就不像是往常使用其他对象的那种方式调用,而是类似于Web服务器的请求与响 应的方式。这个理念跟我设计的Socket池有点不一样。说回线程池里面对线程的管理情况,在没有对线程池提交过任何任务请求的时候,线程池内真正开创的 线程数可并不是那么多,实际上仅仅是小于等于最小的线程数。参照了老赵的代码1 int maxCount = 18; 2 int minCount = 16; 3 ThreadPool.SetMaxThreads(maxCount, maxCount); 4 ThreadPool.SetMinThreads(minCount, minCount); 5 6 Stopwatch watch = new Stopwatch(); 7 watch.Start(); 8 9 WaitCallback callback = i =10 11 Console.WriteLine(String.Format(0: Task 1 started, watch.Elapsed, i);12 Thread.Sleep(10000);13 Console.WriteLine(String.Format(0: Task 1 finished, watch.Elapsed, i);14 ;15 16 for (int i = 0; i 20; i+)17 18 ThreadPool.QueueUserWorkItem(callback, i);19 运行结果如下从上图可以看出,当一开始请求任务的时候,线程池能马上响应去处理任务,16条信息都能在一秒内完成,而这个16则 是刚与最小线程数相等。而老赵的博客上说一秒内创建的线程数会小于最小线程数。估计是我现在用的处理器性能还可以吧。不过我也在单核的虚拟机上运行,同样 也是一秒内创建的线程数跟最小线程数相等。但同时我也发现了另一个情况,就是在真实的电脑上运行上述代码,把最小线程数设成小于4的,同样一开始也能同时 创建了4条线程,个人估计这个跟具有双核四线程的i5CPU有很大关系,在虚拟机上运行就没这情况了。既然初始创建的线程数并非是最大线程数,而是在线程池使用过程中遇到线程不够用了才去创建新线程,直到达到最大值为 止,这样的设计大大节省了对资源的占用。同时也引发了另一个问题,线程的创建速度,这个创建速度会影响到响应请求的时间。每次请求肯定希望尽快得到响应, 但是如果响应的速度过快,万一在一瞬间有大量简短的任务涌入线程池,任务完毕后对已经用完的线程进行回收也是一个比较大的开销。所以这个线程的创建速度也 是得讲究的。1秒内会创建了两个线程,但绝大部分是1秒只创建一个。我自己稍作改动,让结果更清晰些1 Dictionary createTime = new Dictionary(); 2 int maxCount = 12; 3 int minCount = 5; 4 ThreadPool.SetMaxThreads(maxCount, maxCount); 5 ThreadPool.SetMinThreads(minCount, minCount); 6 7 Stopwatch watch = new Stopwatch(); 8 watch.Start(); 9 10 WaitCallback callback = i =11 12 lock (this)13 14 TimeSpan ts = watch.Elapsed;15 if (!createTime.ContainsKey(Thread.CurrentThread.ManagedThreadId)16 17 createTimeThread.CurrentThread.ManagedThreadId = ts;18 Console.WriteLine(0 1 2, Thread.CurrentThread.ManagedThreadId, ts, i);19 20 21 Thread.Sleep(10000);22 ;23 24 for (int i = 0; i 20; i+)25 26 ThreadPool.QueueUserWorkItem(callback, i);27 28 同样运行老赵的代码也不一定能看到每秒创建两个线程,我段代码貌似更难以看见了,估计是因为有了锁的原因。这个结果我试了很多回才弄了出来,好像例子很生硬,但1秒一个线程还是很明显能看出来的。三、池内对象分类在提及获取和设置线程池上下限的部分提及过,一个线程池内有两种类型的线程,一种是工作线程,另一种是IO线程。两 种线程其使用时会有差异,在向线程池发出任务请求的时候,即调用QueueUserWorkItem或者UnsafeQueueUserWorkItem 方法时。使用的线程是工作线程的线程。在使用APM模式时,有部分是使用了工作线程,有部分是使用了IO线程。这里大部分都是使用了工作线程,只有少部分 会使用IO线程。在使用真正的异步方法回调时才会使用IO线程,哪些类的BeginXXX/EndXX方法会真正地用上异步,在鄙人上一篇博文中提到。不 过本人阅读了老赵的博客反复试验之后得出了一个结果,即使是 FileStream,Dns,Socket,WebRequest,SqlCommanddeng的异步操作,它们也会调用到线程池里面的线程。在不同 的阶段调用了不同的线程。那么先看一下下面的代码,要注意一下的是,本人发现如果要把线程池的上下限设成同一个值的话,那只能先设下限再设上限,否则上限 会恢复到默认值的。1 ThreadPool.SetMinThreads(5, 3); 2 ThreadPool.SetMaxThreads(5, 3); 3 ManualResetEvent waitHandle = new ManualResetEvent(false); 4 5 for (int i = 0; i 12 13 FileStream caller = asyncPara.AsyncState as FileStream;14 caller.EndWrite(asyncPara);15 caller.Close();16 caller.Dispose();17 int workC, ioC;18 ThreadPool.GetAvailableThreads(out workC, out ioC);19 Console.WriteLine(String.Format(Write Finish work 0 io 1, workC, ioC);20 waitHandle.WaitOne();21 , fs);22 这里运用到了线程池ThreadPool的GetAvailableThreads方法,方法的描述是获取线程池最大线程数和当前使用线程数的 差值,个人认为就是获取线程池的空闲线程数。在前面的文章中已经提及到,异步方法回调时会开辟线程回调方法,而这条开辟的线程是来自于线程池的,这段代码 中只调用了FileStream类的异步方法,并没有其他调用线程池的方法。看看运行结果可以明显地看出,在异步写文件的操作中,工作线程有被使用,IO线程也有被使用,这个结果跟我之前猜测的有出入。原本以为进行异步操作时,调用 了Begin方法则是利用了系统API去让设备直接访存,在DMA结束之后开辟了一条IO线程去进行方法的回调。但是看了这个情况之后,本人就认为,在调 用了Begin方法之后,线程池使用了一条IO线程去调用系统的API让设备访存,结束后使用的线程却是一条工作线程。假如这时候工作线程已经用完了,那 么对于调用“真异步”或者“假异步”的线程来说都会造成阻塞。当然这里用了回调函数,那么不用回调函数的结果会怎么样。把工作线程设成只有一条。1 ThreadPool.SetMinThreads(1, 5); 2 ThreadPool.SetMaxThreads(1, 5); 3 4 ManualResetEvent waitHandle = new ManualResetEvent(false); 5 for (int i = 0; i 7 8 waitHandle.WaitOne(); 9 );10 string content = hello world;11 content += end;12 byte arr = Encoding.Default.GetBytes(content);13 14 for (int i = 0; i 6; i+)15 16 FileStream fs = new FileStream(test + i + .txt, FileMod

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论