对单个进程集体使用多个线程

Using multiple threads for a single process collectively

我有一个我写的阶乘程序作为基准测试,单线程计算100万的阶乘需要3分钟。我很好奇是否可以将多个线程分配给同一个算法,而不是同时 运行 宁,而是共同地提高处理速度并减少 运行 算法所需的时间。我假设这是可能的,因为超级计算机有很多线程,通常平均 CPU 频率。

显然,如果您有 k 个处理器,您可以将 n 阶乘的工作拆分为并行查找 [2, n * (1/k)], ... [n * ((k-1)/k) + 1, n] 的乘积以获得数字 P_1, ..., P_k,然后整体阶乘为 n! = P_1 * ... * P_k.

正如 Alex 所提到的,这个问题很容易传播到多个线程。

让我们看看使用 Java8 流的单线程实现:

Stream<BigInteger> numbers = LongStream.rangeClosed(1, 1_000_000).mapToObj(BigInteger::valueOf);
BigInteger reduced = numbers.reduce(BigInteger.ONE, BigInteger::multiply);

现在让我们看一下相同的多线程版本:

Stream<BigInteger> numbers = LongStream.rangeClosed(1, 1_000_000).mapToObj(BigInteger::valueOf);
numbers = numbers.parallel();
BigInteger reduced = numbers.reduce(BigInteger.ONE, BigInteger::multiply);

(是的,唯一的区别是numbers = numbers.parallel(); - 流的美丽)

第二个比第一个快(取决于您拥有的真实线程和超线程CPU的数量),但得到的结果相同结果。


由于某些我还不能完全解释的原因,并行版本比非并行版本快很多。它可能与内存使用有关。在我的 4 核 2.5Ghz i7 MacBook Pro 上,使用并行版本计算需要 5.8 秒,但非并行版本即使在 10 分钟内也无法完成(100 万)。

对于 100,000,并行版本要快得多:并行版本为 90 毫秒,非并行版本为 2500 毫秒(在 9 次预热迭代后测量第 10 次迭代)。