线程池行为:不是从最小大小开始增长

本文关键字:小大 开始 线程 | 更新日期: 2023-09-27 18:24:16

我设置了这样的线程池:

ThreadPool.SetMaxThreads(10000, 10000);
ThreadPool.SetMinThreads(20, 20);

然而,我的应用程序在负载过重的情况下开始挂起。这似乎是因为工作任务没有执行:我使用ThreadPool.QueueUserWorkItem来运行一些任务,这些任务又使用相同的方法来排队等待进一步的工作。对于有限的线程池(死锁情况),这显然是危险的,但我使用线程池不是为了限制最大线程数,而是为了减少线程创建开销。

我可以看到潜在的陷阱,但我相信在池中设置最多10000个线程意味着,如果一个项目排队,所有线程都很忙,而池中没有10000个线程,就会创建一个新线程,并在那里处理任务。

然而,我改成了这个:

ThreadPool.SetMaxThreads(10000, 10000);
ThreadPool.SetMinThreads(200, 200);

应用程序开始工作。如果这使它开始工作,我是否错过了线程池如何/何时从最小大小扩展到最大大小的信息?

线程池行为:不是从最小大小开始增长

无论何时使用线程池,都要受其"线程注入和引退算法"的支配。

该算法没有正确记录(据我所知),也不可配置。

如果您使用的是Tasks,您可以编写自己的Task Scheduler

线程池调度程序的工作是确保执行的TP线程不多于cpu内核。默认的最小值等于核心数。这是一个令人满意的数字,因为它最大限度地减少了线程上下文切换带来的开销。调度程序每秒两次介入,并允许另一个线程在现有线程尚未完成的情况下执行。

因此,要达到新的最大值,需要一个小时二十分钟的时间来处理未完成的线程。它不太可能实现,当2000个线程消耗完所有可用的虚拟内存时,一台32位的机器就会崩溃。在一个64位操作系统上,如果有一个非常大的分页文件,你就可以尝试一下了。为了避免分页死亡,需要大量的RAM,至少需要12G。

一般诊断是您不恰当地使用了TP线程。它们花费的时间太长,通常是由I/O阻塞引起的。常规线程是这类工作的正确选择。这可能现在很难解决,尤其是因为你对自己所得到的感到满意。提高最低工资确实是一个快速的解决办法。您将不得不手动调整它,因为TP调度器再也不能做合理的工作了。

您所描述的性能问题与ASP.NET KB文章中所描述的问题类似

http://support.microsoft.com/kb/821268

总之,您需要仔细选择参数(本文提到了默认ASP.NET线程池的典型设置,但您可以将此技巧应用于您的应用程序),并根据性能测试和应用程序的特性对其进行进一步调整。

请注意,你对负载了解得越多,就会发现"重载"不再是描述这种情况的好词。有时您需要对案例进行进一步分类,以包括详细的术语,如突发负载等。

如果您的逻辑依赖于最少的线程数量,则需要紧急更改。

将MinThreads设置为200(甚至20)会浪费相当多的内存。请注意,MaxThreads在这里并不相关,您可能没有10 GB的内存。

事实上,一个最小200帮助你是可疑的,作为一个解决方案,它可能是非常脆弱的。

看看正常的生产者/消费者模式,和/或使用有界队列来耦合您的任务。