一次提交多个相关任务的线程池的推荐大小

Recommended size of a thread pool where several related tasks are submitted once

我正在尝试制作一个程序,该程序将并行执行可变数量的可能(但不一定)计算量大的任务。这些任务(Runnable 类型)将同时提交,一旦所有这些任务完成,线程池应该关闭(换句话说,池只需要接受初始任务,仅此而已)。

在我在此站点上找到的大多数答案中,问题是关于基于服务器的任务(我 运行 我的程序在一个体面的桌面上)或一个在不规则时间接受任务的池间隔。在没有具体使用的问题中,答案通常是"it depends."

我对线程的经验基本为零,所以我真的不知道最佳的"thread count to task intensity"比例是多少。

对于上下文,我正在处理的程序处理矩阵集合(由 3D 数组表示),其中每个矩阵最多可以包含 1000x1000 个元素。其中一个任务可能是进行卷积运算,每个任务都是对集合中的其中一个矩阵进行运算。

是否有针对此类特定问题的建议?

与服务器询问该问题时您听到的相同:不要做出假设,而要做出实验

尝试确定(最坏情况:猜测)您的用户正在使用您的软件的典型硬件设置运行。然后确保您可以很好地进行自动化性能测试。然后看看会发生什么。

但事实是:这不会有太大帮助。你看,当你 运行 你自己的服务器时,你(希望)可以控制这些机器正在处理的工作量。对于桌面设置,远程用户 运行 你的代码在他们的盒子上......你 洞察还有什么 运行ning 在那里。您可能会发现 16 个线程适合 50% 的用户。但其他人可能在他们的机器上做 很多 其他事情,而 16 对他们来说已经太多了。

这才是真正的症结所在。无论您为特定硬件配置找到多少 "good to go",您都无法控制 其他 工作负载。

从这个角度来看,我会相当保守。对于 CPU 密集型工作负载,"too many" 线程无论如何都无济于事,因此请以 CPU 的数量或更好的内核数量作为起点。

除此之外,这里可能真正有用的是:向您的应用程序添加某种 "data gathering"。意思是:让它定期给家里打电话,告诉你类似这样的事情:"this is the hardware I am running on, I am using X threads, and the other workload on the system is Y"。这可能会帮助您获得一些启发式方法,以 适应 最重要的用户设置。但要勤于收集 什么 数据。预先定义您希望得到回答的问题,然后提取回答这些问题所需的数据。

如果您的工作负载是计算密集型的(CPU 限制),您可能需要查看 ForkJoinPool which implements worker stealing

A ForkJoinPool differs from other kinds of ExecutorService mainly by virtue of employing work-stealing: all threads in the pool attempt to find and execute tasks submitted to the pool and/or created by other active tasks (eventually blocking waiting for work if none exist). This enables efficient processing when most tasks spawn other subtasks (as do most ForkJoinTasks), as well as when many small tasks are submitted to the pool from external clients.