为不同类型的任务使用不同的线程池是否值得开销?

Is using different thread pools for different types of tasks worth the overhead?

我正在设计一个 class 来提供有关 Collat​​z 序列组的统计信息。我的目标之一是能够以最大效率同时处理大量包含大量项(数百甚至数千位数字)的序列。

为此,我计划对每个单独的统计数据使用最佳数据收集技术,这意味着 ForkJoinPool 可以更有效地处理某些任务,而标准缓存和固定线程池可以更有效地处理其他任务Executors 中提供。创建多个线程池的开销,或者关闭一个线程池并创建另一个线程池的开销,如果我走那条路,成本会超过我节省的成本吗?

Would the overhead of creating multiple thread pools, or shutting one down and creating another, if I went that route, cost me more than I would save?

我们怎么可能告诉你这个?

关闭和重新启动线程池肯定会产生开销。有种的话。创建线程并不便宜。

但是,我们无法量化使用不同类型的线程池可以节省多少。如果我们无法量化,就无法就您的策略是否有效...向您提供建议。

(但我认为反复关闭并重新创建线程池不是一个好主意。idle 池对性能的影响很小。)


此 "smells" 过早优化。 (这就像在制造发动机缸体之前尝试调整赛车的发动机!)

我的建议是(主要是1)一开始就忘记性能。现在,专注于获得有用的东西。这是我会做的:

  1. 使用最简单的策略实现代码,编写测试用例,测试/调试直到它工作。
  2. 选择一个示例问题或一组您将要尝试解决的典型问题
  3. 实施测试工具,让您可以针对示例问题衡量代码的性能。 (注意 Java 基准测试的标准问题...)
  4. 对您的代码进行基准测试。
    • 速度够快吗?现在停止。
    • 如果没有,继续。
  5. 实施备选策略之一,并测试/调试。
  6. 对修改后的代码进行基准测试。
    • 速度够快吗?现在停止。
    • 看清楚没用吗。放弃它,尝试另一种策略。
    • 你能调整一下吗?如果是这样,请尝试。
  7. 转到5。

此外,以这样一种方式实施不同的策略可能是值得的,您可以使用命令行或配置文件设置调整它们或在它们之间切换。


作为一般规则,很难先验确定任何复杂算法或策略的执行情况。一般来说,理论……或直觉……方法要考虑的因素太多,无法给出可靠的预测。基准测试和调优是必经之路。


1 - 显然,如果您 知道 某些技术或算法会表现不佳,并且您有一个更好的替代方案,其实现的努力大致相同...做明智的事。

由于您只谈论两种不同类型的池(fork-join 和 Executor 基于池),并且您声称至少您的某些任务更适合一种类型或池或另一方面,使用两种类型的池的开销很可能是值得的。

毕竟,您可以让两种类型的池都保持活动状态,因此设置池和创建线程只需要 一次 成本,而(显然) 这两种池类型的好处将适用于整个处理过程。由于您正在做 "enormous" 的工作量,即使是很小的收益最终也会加起来并超过一次性成本(这可能以每个线程的微体系结构来衡量)。

这一观察的关键在于,对于您未使用的池中现有但不活动的线程,没有真正的持续开销。

当然说了,简答吧"just try both approaches and measure it!"。