线程池不立即启动新线程

6

我有一个C#的Windows服务,它启动了多个对象(类库)。每个对象都有自己的“处理”逻辑,通过使用ThreadPool启动了多个长时间运行的处理线程。这里有一个示例:

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

这很好用。我的应用程序没有问题,我的线程也工作得很好。

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

我已经切换了从 ThreadPoolThread,并且问题解决了。这里可能发生了什么? 我知道我没有超过 MaxThreads 计数(最多启动20个线程)。


那绝对不应该发生,而且我也没有遇到过。你的控制台应用程序还做了其他事情吗?如果你创建一个全新的控制台应用程序,并输入 ThreadPool.QueueUserWorkItem(o => Console.WriteLine("test"));,它会出现同样的问题吗? - RandomEngy
1
如果您想查看ThreadPool正在执行的操作,我建议运行Process Explorer并关注进程中的线程。您可以看到有多少个线程池线程正在被启动。如果您的操作需要很长时间才能完成,那么可能需要一段时间才能将线程增加到20个。 - RandomEngy
2个回答

15

ThreadPool 不适用于长时间运行的任务(更确切地说,当你使用 ThreadPool 时,甚至不一定会启动新线程,因为它的目的是将任务分配到有限的线程数量上)。

如果你的任务需要长时间运行,应该将其拆分为逻辑部分并将这些部分放到 ThreadPool 上(或使用新的 Task 框架),或者自己创建一个 Thread 对象。

关于为什么会出现延迟,MSDN 的 ThreadPool 类文档 中有如下解释:

作为其线程管理策略的一部分,线程池在创建线程之前会延迟。因此,当一系列任务在短时间内排队时,可能会出现所有任务开始之前的显著延迟。

我们只知道 ThreadPool 还未达到其最大线程数,但不清楚有多少线程(如果有)正在闲置等待。


好的,谢谢提供信息!我会用Thread对象替换它们,并研究Task对象以备将来开发之需。谢谢! - MattW
3
如果线程池中仍有(据说)可用的自由线程,为什么这会导致延迟呢?我同意结论,但不认为这个答案令人满意地回答了“为什么”的问题。 - user166390
2
@pst:你不知道线程池中是否有可用的空闲线程,你只知道ThreadPool还没有达到最大线程数。根据MSDN文档所述,ThreadPool会延迟创建新线程,因此一次添加多个项几乎肯定会导致延迟。请参考我的编辑。谢谢! - Adam Robinson
@Adam Robinson 给出了更加详尽的回答,赞一个。 - user166390

4
线程池的最大线程数是它可以创建的最大数量,而不是已经创建的最大数量。线程池有逻辑来防止它立即启动一堆线程。
如果您快速连续调用ThreadPool.QueueUserWorkItem 10次,则线程池不会立即创建10个线程。它会启动一个线程,延迟一段时间后再启动另一个线程,以此类推。
我记得延迟时间为500毫秒,但我找不到文档来验证这一点。
在这里:托管线程池
线程池在启动新的空闲线程之前有内置延迟(在 .NET Framework 2.0 中为半秒)。如果您的应用程序周期性地在短时间内启动许多任务,则稍微增加空闲线程数可以显著提高吞吐量。将空闲线程数设置过高会不必要地消耗系统资源。
您可以使用GetMinThreads和SetMinThreads来控制线程池维护的空闲线程数。
请注意,此引用摘自文档的.NET 3.5版本。.NET 4.0版本没有提到延迟。

6
需注意的一点是,ThreadPool.SetMinThreads 并不会实际增加线程池中维护的空闲线程数量。它只是表示当实际线程数低于该数字时,线程池将根据需求创建新的线程,而不是等待之前的线程完成。 - RandomEngy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接