Java 要获得最大性能,线程池的大小应该是多少?

Java 要获得最大性能,线程池的大小应该是多少?,java,multithreading,concurrency,Java,Multithreading,Concurrency,我最近遇到了一个评估问题: ExecutorService threadpool = Executors.newFixedThreadPool(N); for(Runnable task : tasks){ threadpool.submit(task); } 每个任务花费25%用于计算,75%用于I/O。假设我们使用的是四核机器(没有超线程),那么线程池N的大小应该是多少才能在不浪费线程的情况下实现最大性能?(假设我们有无限的I/O容量) 我猜是16,因为机器有无限的I/O,这意味

我最近遇到了一个评估问题:

ExecutorService threadpool = Executors.newFixedThreadPool(N);

for(Runnable task : tasks){
    threadpool.submit(task);
}
每个任务花费25%用于计算,75%用于I/O。假设我们使用的是四核机器(没有超线程),那么线程池N的大小应该是多少才能在不浪费线程的情况下实现最大性能?(假设我们有无限的I/O容量)

我猜是16,因为机器有无限的I/O,这意味着我们可以完全专注于CPU。每个任务在运行时使用四分之一的CPU。这意味着,我们可以运行四个任务来饱和一个CPU内核,这使得在四核机器上N=16


更新:此问题的选项为2、4、5、6、7、8、12和16。

您应该考虑饱和核心。不过,最好的答案将超过16个。如果您只有16个线程,那么CPU需求不会完全一致,因此您的所有内核都在使用中

因此,最好的答案是>16,但也足够小,不会显著增加单个任务的完成时间,造成显著的线程切换成本,或者浪费大量内存

如果你在课堂上学会了这一点,那么你的教授可能会给你乘数作为“经验法则”。他希望你记住它,并在这里应用它

我通常使用average_demand=2*num_内核,因此会选择32个线程。这在大多数情况下都很有效。当平均CPU需求是内核数量的两倍时,内核利用率将非常接近100%

此外,在这种情况下,每个任务的CPU部分平均只获得1/2的内核,因此它需要两倍的时间。。。但这只占工作的25%,因此任务完成时间只比最佳时间多13%

我使用的2倍默认值几乎总是高于最佳值,但它也几乎总是足够低,不会造成显著的额外开销。如果您知道您的任务非常受CPU限制,那么您可以自信地减少这个数量

如果你真的想找到最佳值,那么你可以测量它,但是当你的值在正确的范围内时,不会有太大的差别

--


注:我上面使用的“平均需求”是在给定N个线程和N个内核的情况下,在任何时候使用的预期内核数。

虽然这个问题没有严格正确或错误的答案,但主观上好的答案是:

32个线程

你必须从概率的角度考虑。 现在让我们考虑一个CPU核心和独立线程:

一个线程在任何给定时间进行计算的几率为25%。 如果有两个独立的线程(概率事件),则至少有一个线程执行某些CPU工作的概率不是50%,而是7/16(43.75%)。(如果您对此不确定,您应该刷新其中一些)

你可能知道这是怎么回事。要使P为100%,线程数必须是无限的。因此,我们必须做出有根据的猜测:
4个螺纹的P值约为68%,8个螺纹的P值约为90%。现在数到8点真的是徒劳无益的,所以我们定在8点。这是一个核心。我们有4个CPU核,因此我们可以将其乘以4,得到最终答案:32。

你的答案是什么,你是如何得出的,为什么你不认为这是正确的答案?我的答案是16,因为机器有无限的I/O,这意味着我们可以完全专注于CPU。每个任务在运行时使用四分之一的CPU。这意味着,我们可以运行四个任务来饱和一个CPU内核,这使得四核机器上的N=16。听起来对我来说是正确的答案。但这不是正确的解决方案。我没有得到任何反馈。根据Goetz和Subramaniam关于IO绑定任务的公式,16是答案。