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

标签 java multithreading tomcat threadpool

自定义线程池的推荐大小是 number_of_cores + 1(参见 herehere)。所以假设在一个有 2 个内核的系统上有一个 Spring 应用程序,配置是这样的

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

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

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

min, max and average response times in milliseconds

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

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

最佳答案

您链接到的两个页面都明确表示这仅适用于未阻塞的 CPU 绑定(bind)任务。

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

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


Good advice comes with a rationale so you can tell when it becomes bad advice. If you don’t understanding why something should be done, then you’ve fallen into the trap of cargo cult programming, and you’ll keep doing it even when it’s no longer necessary or even becomes deleterious.

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

关于java - 线程池大小应远大于核心数 + 1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34278203/

相关文章:

python - 如何将tcp服务器放在python中的另一个线程上

java - 本地主机上的服务器 Tomcat v9.0 服务器无法在 eclipse 中启动

java - 在具有 tomcat 目录结构的项目中从 java 访问 js 文件(java.io.FileNotFoundException)

java - 开始认为 Maven 对于我当前的项目来说太过分了

java - Android 条形 Activity 指示器

java - 以编程方式创建环境变量

c# - 如何在条件语句中使用 Linq 的 .Count() 方法

java - 没有 getter/setters/toString/constructors 的清晰代码的 Lombok 替代方案

java - 如何在不阻塞的情况下在 Java 中调用 notify()?

tomcat - Tomcat 中的 LDAP 错误 - 需要 TLS secret 性