推荐的corePoolSize传递给ThreadPoolExecutor / ScheduledThreadPoolExecutor的内容是什么?
Runtime.getRuntime().availableProcessors()
?
Runtime.getRuntime().availableProcessors() * 2
?
从某一点来说,我希望100%使用CPU(所有核心),尽可能少地使用它,以便尽快完成并且不会太多上下文转换的惩罚。
另一方面,某些线程可能不会一直使用CPU,例如等待网络。在这种情况下,我希望生成新线程并保持所有内核忙碌。
我可以暂时过度使用CPU了。比未使用和未处理的任务更好。
那么如何实现这种线程负载平衡呢?感谢。
答案 0 :(得分:4)
调整线程池的大小取决于您要在该池上执行的任务的性质。作为一般规则,它取决于等待时间和CPU时间之间的比率以及可用的cpu数量。
适用的一般公式是:
使处理器保持所需利用率的最佳池大小为:
您可以在Java Concurrency In Practice的 8.2调整线程池部分找到更多信息。
答案 1 :(得分:1)
我认为这取决于你在做什么。您已经提到某些线程可能正在等待I / O.
corePoolSize
是池将保留的线程数,即使空闲也是如此。我想你想要设置最大池大小。
上下文切换开销总是存在,并且我认为它实际上不会随着更多线程而增加,因为切换通常被实现为常量切片(即,时间切片不会与可运行线程的数量成反比地减少)
您显然需要至少与核心一样多的线程来实现完全加载,您需要多少额外线程取决于线程完成的速度以及I / O需要多长时间。
一个选项是在具有较大池大小的单独步骤中执行I / O,以确保始终有一个I / O步骤已完成(CompletableFuture对此很方便)。然后,对于下一步,您将使用一个单独的ThreadPool,其池大小与一个线程完成后将从上一步骤获取的核心数相同。
像这样(未经证实):
CompletableFuture.supplyAsync(ioTask, ioExecutorWithLargePool)
.thenAccept(cpuBoundTask, executorWithCpuCoreSizedPool);
答案 2 :(得分:1)
您可以查看Amdahl's law来定义核心数量。将您的程序视为单线程程序,并查看可以并行化的位置。这可以让你了解N(这里我们可以通过应用程序的线程数来估算核心数量。)
根据我的经验,确定“最佳”线程数量的最佳方法仍然是创建多线程程序,并使用尽可能多的线程数值进行测试,并查看哪一个输出最佳性能。 (另见Optimal number of threads per core)
答案 3 :(得分:1)
除了john16384的回答:
如果您的CPU支持每个CPU核心两个线程(多线程),那么您的代码Runtime.getRuntime().availableProcessors()? Runtime.getRuntime().availableProcessors() * 2
可能是一个好主意。