VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > c#编程 >
  • C#线程 入门—优化线程池

优化线程池

线程池从其池中的一个线程开始。分配任务后,池管理器会“注入”新线程以应对额外的并发工作负载(最大限制)。在足够长时间的不活动之后,如果池管理器怀疑这样做会导致更好的吞吐量,则可以“退出”线程。

您可以通过调用ThreadPool.SetMaxThreads;来设置池将创建的线程的上限。默认值为:

  • 32位环境中Framework 4.0中的1023
  • 在64位环境中的Framework 4.0中为32768
  • 框架3.5中的每个核心250个
  • Framework 2.0中每个内核25个

(这些数字可能会因硬件和操作系统而异。)之所以有很多原因,是为了确保某些线程被阻塞(在等待某种条件(例如,来自远程计算机的响应)时处于空闲状态)的进度。

您还可以通过调用ThreadPool.SetMinThreads设置下限。下限的作用是微妙的:这是一种高级优化技术,它指示池管理器在达到下限之前不要延迟线程的分配。当线程被阻塞时,提高最小线程数可提高并发性(请参见侧栏)。

默认的下限是每个处理器内核一个线程-允许全部CPU利用率的最小值。但是,在服务器环境(例如IIS下的ASP.NET)上,下限通常要高得多-多达50个或更多。

 

最小线程数如何工作?

 

实际上,将线程池的最小线程数增加到x并不会实际上强制立即创建x个线程-线程仅根据需要创建。相反,它指示池管理器在需要它们时立即最多创建x个线程。那么,问题是,为什么在需要时线程池会延迟创建线程的时间呢?

答案是防止短暂的短暂活动导致线程的完全分配,从而突然膨胀应用程序的内存空间。为了说明这一点,请考虑运行一个客户端应用程序的四核计算机,该应用程序一次可处理40个任务。如果每个任务执行10毫秒的计算,则假设工作在四个核心之间分配,整个任务将在100毫秒内结束。理想情况下,我们希望40个任务恰好在四个线程上运行:

  • 减少一点,我们就不会充分利用这四个核心。
  • 再有,我们将浪费内存和CPU时间来创建不必要的线程。

这正是线程池的工作方式。只要将线程数与内核数进行匹配,只要有效地使用了线程(在这种情况下就是这样),程序就可以在不影响性能的情况下保留较小的内存占用。

但是现在假设,每个任务而不是工作10毫秒,而是查询Internet,在本地CPU空闲时等待半秒以响应。池管理器的线程经济策略崩溃了;现在创建更多线程会更好,因此所有Internet查询都可以同时发生。

幸运的是,池管理器有一个备份计划。如果其队列保持静止状态超过半秒,它将通过创建更多线程(每半秒一个)来响应,直至达到线程池的容量。

延迟的半秒是一把两刃剑。一方面,这意味着一次短暂的短暂活动不会使程序突然消耗掉不必要的40 MB(或更多)内存。另一方面,当池中的线程阻塞时,例如查询数据库或调用WebClient.DownloadFile时,它可能不必要地延迟事情。因此,可以通过调用SetMinThreads来告诉池管理器不要延迟前x个线程的分配:

ThreadPool.SetMinThreads(5050);

(第二个值指示要分配给I / O完成端口的线程数,由APM使用,具体请参见C#4.0第23章的内容。)

默认值为每个内核一个线程。


相关教程