【问题标题】:Java thread pool: is it better to have lots of smaller tasks, or less task with larger batchesJava线程池:有很多小任务更好,还是有大批量任务更少
【发布时间】:2012-05-30 07:07:14
【问题描述】:

我们目前正在尝试通过在我们的 Java 应用程序中使用多线程来调整性能。 我们有一个长时间运行的串行任务,我们希望将其拆分为多个 CPU 内核。

基本上我们有一个清单,假设有 100.000 个项目/要做的事情。

我现在的问题是这样做更好:

选项 1(伪代码):

for(i = 0; i < 100000; i++){
  threadpool.submit(new MyCallable("1 thing to do"))
}

这会将 100000 个可运行/可调用对象添加到线程池的队列(当前 LinkedBlockingQueue)

或者这样做更好: 选项 2(伪代码)

for(i = 0; i < 4; i++){
  threadpool.submit(new MyCallable("25000 things to do"))
}

我们已经尝试了选项 1,但我们没有注意到任何性能提升,尽管我们可以清楚地看到多个线程疯狂地工作并且使用了 4 个 CPU 内核。但我的感觉是,由于任务众多,选项 1 中存在一些开销。我们还没有尝试过选项 2,但我的感觉是,它可以加快速度,因为开销更少。我们基本上将列表分成 4 个更大的块,而不是 100000 个单项。

对此有什么想法吗?

谢谢

【问题讨论】:

  • 对此没有一个通用的答案。这取决于“要做的事情”的性质。您必须进行实验。
  • 感谢您提供有用的答案。我知道没有通用的答案,但我想了解每种方法。我们的用例是计算密集型而不是 I/O 限制。我们现在将实施方案 2 并比较结果。

标签: java multithreading threadpool


【解决方案1】:

重要的是您要尽量减少上下文切换的数量,并最大限度地增加每个任务花费在计算上的工作量。实际上,如果您的任务是计算,那么超过物理 CPU 的数量将无济于事。如果您的任务实际上执行了很多 I/O 和 I/O 等待,那么您希望拥有许多这样的任务,以便在一个阻塞时总是有一堆“就绪”任务可用。

如果你真的有 25000 件事情要做,而且这些事情是计算,我可能会设置 32 个线程(比你拥有的 CPU 更多,但不会产生太多额外开销)并分配 10-50 个工作单元如果这些单位相对较小,则分配给每个单位。

【讨论】:

    【解决方案2】:

    您的分析是正确的:批处理项目的成本(内存、上下文切换和一般指令计数)会更少 - 至少一般来说是这样。

    但是,随着单个任务变得越来越大,这变得越来越不重要 - 如果您已经将 99% 的时间用于工作,而不是线程池开销或对象创建,那么您只能以这种方式优化剩下的 1%。

    【讨论】:

      【解决方案3】:

      嗯,这取决于您的用例。

      在性能方面,我认为拥有较大的工作块比较小的线程数要好。上下文切换会更少,因此可以节省 CPU 周期和 RAM。

      当任务数量较少时,这可能无关紧要,但是,如果您有 10000 个线程,这很重要。

      【讨论】:

        【解决方案4】:

        您的机器中有 N 个内核。您想利用所有内核,但开销最小。因此,如果任务大小相等,则任务的最小数量可能为 N。如果它们不相等,则拥有 M*N 个任务可能会更好,因为这可能意味着即使某些任务相对较短,所有内核也同样繁忙。例如一个核心执行一项长任务,而另一个核心执行三个短任务。在我的大多数用例中,我使用 2-4 的 M。

        如果可以,您可以对运行时间较长的任务进行排序,以便首先启动以获得最佳平衡。即在添加任务之前将任务从最长到最短排序。

        例如如果您有 8 个内核,您可能会发现 8 个任务最适合 CPU 密集型处理。对于 IO 绑定处理或需要不同时间量的任务,2*8 到 4*8 的任务可能是最佳的。

        【讨论】:

          【解决方案5】:

          4 个批次的问题可能是,如果其中一个在 10 分钟内完成,而其中三个在 20 分钟内完成,则 1 个核心将在 10 分钟内不使用,而其他 3 个线程将在 3 个核心上处理项目。但是您对开销是正确的。但是验证的唯一方法是检查它,因为很多事情取决于您的数据。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-10-03
            • 1970-01-01
            • 2016-06-24
            • 2019-11-08
            • 2016-11-02
            • 2013-01-18
            • 2022-01-18
            • 2011-09-29
            相关资源
            最近更新 更多