传递给ThreadPoolExecutor / ScheduledThreadPoolExecutor的推荐corePoolSize是什么?

时间:2017-02-28 08:56:58

标签: java multithreading threadpoolexecutor

推荐的corePoolSize传递给ThreadPoolExecutor / ScheduledThreadPoolExecutor的内容是什么?

Runtime.getRuntime().availableProcessors()Runtime.getRuntime().availableProcessors() * 2

从某一点来说,我希望100%使用CPU(所有核心),尽可能少地使用它,以便尽快完成并且不会太多上下文转换的惩罚。

另一方面,某些线程可能不会一直使用CPU,例如等待网络。在这种情况下,我希望生成新线程并保持所有内核忙碌。

我可以暂时过度使用CPU了。比未使用和未处理的任务更好。

那么如何实现这种线程负载平衡呢?感谢。

4 个答案:

答案 0 :(得分:4)

调整线程池的大小取决于您要在该池上执行的任务的性质。作为一般规则,它取决于等待时间和CPU时间之间的比率以及可用的cpu数量。

适用的一般公式是:

Sizing Threads Pools

使处理器保持所需利用率的最佳池大小为:

Optimal thread-pool sizing

您可以在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可能是一个好主意。