线程池大小应远大于核心数 + 1

Posted

技术标签:

【中文标题】线程池大小应远大于核心数 + 1【英文标题】:Thread pool size should be much more than number of cores + 1 【发布时间】:2016-03-20 14:14:03 【问题描述】:

自定义线程池的推荐大小为 number_of_cores + 1(请参阅 here 和 here)。因此,假设系统上有一个具有 2 个核心的 Spring 应用程序,并且配置是这样的

<task:executor id="taskExecutor" 
pool-size="#T(java.lang.Runtime).getRuntime().availableProcessors() + 1" />
<task:annotation-driven executor="taskExecutor" />

在这种情况下,多个请求之间将共享一个 ExecutorService。所以如果有 10 个请求到达服务器, 在 ExecutorService 中只能同时执行其中的 3 个。这可能会造成瓶颈,并且随着请求数量的增加,结果会变得更糟(请记住:默认情况下,tomcat 最多可以同时处理 200 个请求 = 200 个线程)。如果没有任何池化,该应用程序的性能会更好。

通常一个内核一次可以处理多个线程。 例如我创建了一个服务,它调用了两次https://httpbin.org/delay/2。每个调用需要 2 秒来执行。因此,如果不使用线程池,服务平均响应时间为 4.5 秒(用 20 个同时请求进行测试)。 如果使用线程池,则响应因池大小和硬件而异。我在具有不同池大小的 4 核机器上运行测试。以下是以毫秒为单位的最小、最大和平均响应时间的测试结果

从结果可以得出结论,最佳平均时间是最大池大小。池中有 5 个(4 核 + 1)线程的平均时间比没有池的结果还要差。所以在我看来,如果一个请求不会占用太多 CPU 时间,那么将线程池限制为 Web 应用程序中的核心数 + 1 是没有意义的。

对于 CPU 要求不高的 Web 服务,在 2 核或 4 核机器上将池大小设置为 20(甚至更多)有什么问题吗?

【问题讨论】:

【参考方案1】:

您链接到的两个页面都明确表示这仅适用于未阻塞的、受 CPU 限制的任务。

您的任务在远程计算机上被阻止等待,因此此建议不适用。

忽略不适用于您的建议并没有错,因此您可以而且应该增加线程池大小。


好的建议是有理由的,所以当它变成坏的建议时,你可以知道。如果你不明白为什么应该做某事,那么你就陷入了货物崇拜编程的陷阱,即使不再需要甚至变得有害,你也会继续这样做。

Raymond Chen,在他的博客“The Old New Thing”上

【讨论】:

在我看来,我提供的两个链接都没有明确说明“畅通的、受 CPU 限制的任务”。在 Web 应用程序(今天的大多数应用程序)中,您很少有仅受 CPU 限制的代码(DB 调用、WS 调用......),因此阿姆达尔定律可以在少数情况下应用。无论如何,感谢您的明确解释

以上是关于线程池大小应远大于核心数 + 1的主要内容,如果未能解决你的问题,请参考以下文章

线程池工作机制

线程池大小设置,CPU的核心数线程数的关系和区别,同步与堵塞完全是两码事

线程池大小设置,CPU的核心数线程数的关系和区别,同步与堵塞完全是两码事

线程池大小如何调?

线程池的执行流程?

线程池的执行流程?