ThreadPool 没有立即启动新线程

Posted

技术标签:

【中文标题】ThreadPool 没有立即启动新线程【英文标题】:ThreadPool not starting new Thread instantly 【发布时间】:2011-11-27 21:12:35 【问题描述】:

我有一个启动各种对象(类库)的 C# Windows 服务。这些对象中的每一个都有自己的“处理”逻辑,它们使用ThreadPool 启动多个长时间运行的处理线程。我有一个例子,就像这样:

System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(WorkerThread_Processing));

这很好用。我的应用运行正常,我的线程运行良好。

现在,对于回归测试,我正在启动这些相同的对象,但从 C# 控制台应用程序而不是 Windows 服务启动。它调用了完全相同的代码(因为它调用了相同的对象),但是WorkerThread_Processing 方法在开始前最多延迟 20 秒。

我已经进去并从ThreadPool 切换到Thread,问题就消失了。这里会发生什么?我知道我没有超过 MaxThreads 计数(我最多启动 20 个线程)。

【问题讨论】:

这绝对不应该发生,也不会发生在我身上。您的控制台应用程序是否在做其他事情?如果您创建一个全新的控制台应用程序并输入ThreadPool.QueueUserWorkItem(o => Console.WriteLine("test"));,它会做同样的事情吗? 此外,如果您想查看 ThreadPool 正在做什么,我建议您运行 Process Explorer 并密切关注进程中的线程。您可以看到有多少线程池线程正在启​​动。如果您的操作需要很长时间才能完成,则可能需要一段时间才能增加到 20 个线程。 【参考方案1】:

ThreadPool 专门用于长期运行的项目(更具体地说,当您使用 ThreadPool 时,您甚至不必启动新线程,因为它的目的是将任务分散到有限数量的线程上)。

如果您的任务运行时间很长,您应该将其分解为放在ThreadPool 上的逻辑部分(或使用新的Task 框架),或者启动您自己的Thread 对象。

至于为什么您会遇到延迟,MSDN Documentation for the ThreadPool class 说明如下:

作为其线程管理策略的一部分,线程池在创建线程之前会延迟。因此,当多个任务在短时间内排队时,在所有任务启动之前可能会有很大的延迟。

您只知道ThreadPool 没有达到它的最大线程数,而不是它实际上有多少线程(如果有的话)处于空闲状态。

【讨论】:

好的,谢谢你的信息!我将用 Thread 对象替换它们,并研究 Task 对象以供将来开发。谢谢! 但是,如果池中(据说)还有空闲线程,为什么会导致延迟呢?我同意这个结论,但认为这个答案不能令人满意地回答为什么 @pst:你不知道池中还有空闲线程,你知道ThreadPool 还没有达到它的最大线程数。根据MSDN Docs 的说法,ThreadPool 将延迟创建新线程,因此一次添加多个项目几乎可以保证会产生延迟。请参阅我的编辑。谢谢! @Adam Robinson 更彻底的答案,+1。【参考方案2】:

线程池的最大线程数值是它可以创建的最大数量。它不是已经创建的最大数量。线程池具有防止它立即启动一大堆线程的逻辑。

如果快速连续调用ThreadPool.QueueUserWorkItem 10 次,线程池不会立即创建10 个线程。它将启动一个线程、延迟、启动另一个等。

我似乎记得延迟是 500 毫秒,但我找不到文档来验证这一点。

这里是:The Managed Thread Pool:

线程池具有内置延迟(.NET 中为半秒 框架版本 2.0) 在开始新的空闲线程之前。如果你的 应用程序在短时间内周期性地启动许多任务,一个小的 空闲线程数量的增加会产生显着的 吞吐量的增加。将空闲线程数设置得太高 不必要地消耗系统资源。

可以控制线程维护的空闲线程数 使用 GetMinThreads 和 SetMinThreads 池

请注意,此引用取自 .NET 3.5 版本的文档。 .NET 4.0 版本没有提到延迟。

【讨论】:

需要注意的重要一点是ThreadPool.SetMinThreads 实际上并没有增加线程池中维护的空闲线程的数量。它只是意味着当实际线程数低于该数量时,线程池将按需创建新线程,而不是等待之前的线程完成。

以上是关于ThreadPool 没有立即启动新线程的主要内容,如果未能解决你的问题,请参考以下文章

ThreadPool线程池

ThreadPool线程池

ThreadPool类(线程池)

ThreadPool.SetMinThreads 不创建任何新线程

如何创建和启动一个线程

java核心知识点 --- 线程池ThreadPool