【问题标题】:What should be the size of thread pool to achieve maximum performance?线程池的大小应该是多少才能达到最大性能?
【发布时间】:2016-08-08 06:33:54
【问题描述】:

我最近在评估时遇到了这个问题:

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,因为机器有无限的 I/O,这意味着我们可以完全专注于 CPU。每个任务在运行时使用四分之一的 CPU。这意味着,我们可以运行四个任务以使一个 CPU 核心饱和,这使得 N=16 在四核机器上。
  • 听起来对我来说是正确的答案。
  • 但这不是正确的解决方案。我没有收到任何反馈。
  • 根据this blog,根据 Goetz 和 Subramaniam 的 IO Bound Tasks 公式,16 是答案。

标签: java multithreading concurrency


【解决方案1】:

你是正确的,你应该考虑让你的核心饱和。不过,最好的答案将超过 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 个内核的情况下随时使用的预期内核数。

【讨论】:

    【解决方案2】:

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

    32 个线程

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

    一个线程在任何给定时间都有 25% 的机会进行计算。 如果你有 2 个独立线程(概率事件),那么至少有一个线程做一些 CPU 工作的概率不是 50%,而是 7/16(43.75%)。 (如果你不确定,你应该刷新一些probability skills)。

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

    【讨论】:

      猜你喜欢
      • 2016-12-19
      • 2021-09-28
      • 2021-10-03
      • 2016-09-01
      • 2022-12-29
      • 2011-01-26
      • 1970-01-01
      • 2012-03-05
      • 1970-01-01
      相关资源
      最近更新 更多