我最近在评估时遇到了这个问题:
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_cores,所以会选择32个线程。这在大多数情况下效果很好。当平均CPU需求是核心数的两倍时,核心利用率将非常接近100%。
此外,在这种情况下,每个任务的 CPU 部分平均只获得 1/2 核心,因此需要两倍的时间...但这只是工作的 25%,因此任务完成时间仅为 13%超过最佳状态。
我使用的 2 倍默认值几乎总是高于最佳数字,但它也几乎总是足够低,不会造成显着的额外开销。如果您知道您的任务严重依赖 CPU,那么您可以放心地减少此数字。
如果你真的想找到最佳值,那么你可以测量它,但是当你在正确的范围内时,它不会产生太大的差异。
--
P.S 注意:我上面使用的“average_demand”是在给定 N 个线程和 N 个核心的情况下任何时候使用的预期核心数量。
关于java - 为了获得最大性能,线程池的大小应该是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38817220/