线程池行为:不从最小大小开始增长
我已经像这样设置了我的线程池:
ThreadPool.SetMaxThreads(10000, 10000);
ThreadPool.SetMinThreads(20, 20);
但是,我的应用程序开始在重负载下挂起。这似乎是因为工作任务没有执行:我使用 ThreadPool.QueueUserWorkItem 来运行一些任务,这些任务又使用相同的方法来排队进一步的工作。对于有限的线程池(死锁情况),这显然是危险的,但我使用线程池不是为了限制最大线程数,而是为了减少线程创建开销。
我可以看到那里潜在的陷阱,但我相信在池上设置最大 10000 个线程意味着如果一个项目已排队,所有线程都忙,并且池中没有 10000 个线程,则新的线程将在那里创建并处理任务。
但是,我更改为:
ThreadPool.SetMaxThreads(10000, 10000);
ThreadPool.SetMinThreads(200, 200);
..应用程序开始工作。如果这使它开始工作,我是否错过了有关线程池如何/何时从最小尺寸扩展到最大尺寸的信息?
I had set up my thread pool like this:
ThreadPool.SetMaxThreads(10000, 10000);
ThreadPool.SetMinThreads(20, 20);
However, my app started hanging under heavy load. This seemed to be because worker tasks were not executing: I had used ThreadPool.QueueUserWorkItem
to run some tasks which in turn used the same method to queue further work. This is obviously dangerous with a limited thread pool (a deadlock situation), but I am using a thread pool not to limit maximum threads but to reduce thread creation overhead.
I can see the potential trap there, but I believed that setting a maximum of 10000 threads on the pool would mean that if an item was queued, all threads were busy, and there weren't 10000 threads in the pool, a new one would be created and the task processed there.
However, I changed to this:
ThreadPool.SetMaxThreads(10000, 10000);
ThreadPool.SetMinThreads(200, 200);
..and the app started working. If that made it start working, am I missing something about how/when the thread pool expands from minimum toward maximum size?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
每当你使用线程池时,你都会受到它的“线程注入和退休算法”的支配。
该算法没有正确记录(据我所知)并且不可配置。
如果您使用任务,则可以编写自己的任务计划程序
Whenever you use the thread pool, you are at the mercy of its "thread injection and retirement algorithm".
The algorithm is not properly documented ( that I know of ) and not configurable.
If you're using Tasks, you can write your own Task Scheduler
线程池调度程序的工作是确保执行 TP 线程的数量不超过 cpu 核心数。默认最小值等于核心数。这是一个令人高兴的数字,因为它最大限度地减少了线程上下文切换带来的开销。如果现有线程尚未完成,调度程序会每秒两次介入并允许另一个线程执行。
因此,需要一个小时二十分钟的时间来完成未完成的线程才能达到新的最大值。这是不太可能实现的,当 2000 个线程耗尽所有可用虚拟内存时,32 位计算机就会崩溃。您可以在具有非常大的分页文件的 64 位操作系统上尝试一下。需要大量 RAM 才能避免分页死亡,至少需要 12 GB。
一般诊断是您不恰当地使用 TP 线程。它们花费的时间太长,通常是由于 I/O 阻塞造成的。常规线程是此类作业的正确选择。现在这个问题可能很难解决,尤其是当你对自己所拥有的感到满意的时候。提高最小值确实是一个快速的解决方法。您必须手动调整它,因为 TP 调度程序无法再完成合理的工作。
The job of the threadpool scheduler is to ensure there are no more executing TP threads than cpu cores. The default minimum is equal to the number of cores. A happy number since that minimizes the overhead due to thread context switching. Twice a second, the scheduler steps in and allows another thread to execute if the existing ones haven't completed.
It will therefore take a hour and twenty minutes of having threads that don't complete to get to your new maximum. It is fairly unlikely to ever get there, a 32-bit machine will keel over when 2000 threads have consumed all available virtual memory. You'd have a shot at it on a 64-bit operating system with a very large paging file. Lots of RAM required to avoid paging death, you'd need at least 12 gigabytes.
The generic diagnostic is that you are using TP threads inappropriately. They take too long, usually caused by blocking on I/O. A regular Thread is the proper choice for those kind of jobs. That's probably hard to fix right now, especially since you're happy with what you got. Raising the minimum is indeed a quick workaround. You'll have to hand-tune it since the TP scheduler can't do a reasonable job anymore.
中记录的问题类似
您描述的性能问题与此 ASP.NET 知识库文章http://support .microsoft.com/kb/821268
总而言之,您需要仔细选择参数(本文提到了默认 ASP.NET 线程池的典型设置,但您可以将技巧应用到您的应用程序中),并进一步根据性能调整它们测试和您的应用程序的特征。
请注意,您对负载了解得越多,您就会发现“重负载”不再是描述这种情况的好术语。有时您需要对案例进行进一步分类,以包含详细术语,例如突发负载等。
The performance issue you described, is similar to what is documented in this ASP.NET KB article,
http://support.microsoft.com/kb/821268
To summarize, you need to carefully choose the parameters (this article mentions the typical settings for default ASP.NET thread pool, but you can apply the trick to your app), and further tune them based on performance testing and the characteristics of your app.
Notice that the more you learn about load, you will see that "heavy load" is no longer a good term to describe the situation. Sometimes you need to further categorize the cases, to include detailed term, such as burst load, and so on.
如果您的逻辑依赖于最小数量的线程,那么您需要紧急更改它。
将 MinThreads 设置为 200(甚至 20)会浪费大量内存。请注意,MaxThreads 在这里无关紧要,您可能没有 10 GB 内存。
200 分钟就能帮助您解决问题这一事实是值得怀疑的,而且作为解决方案,它可能非常脆弱。
查看正常的生产者/消费者模式,和/或使用有界队列来耦合您的任务。
If your logic depends on having a minimum amount of threads you need to change that, urgently.
Setting a MinThreads of 200 (or even 20) is wasting quite a bit of memory. Note that the MaxThreads won't be relevant here, you probably don't have the 10 GB mem for that.
The fact that a min of 200 helps you out is suspicious and as a solution it is probably very brittle.
Take a look at normal Producer/Consumer patterns, and/or use a bounded queue to couple your tasks.