[英]Why does this multi threaded parallel program executes close to sequential time?
在下面的程序中,我安排了少量线程,每个线程执行一个受 CPU 限制的长时间运行的单线程计算,该计算不使用任何锁并使 Apple M1 的核心饱和。 我使用的线程少于物理内核。
该程序在CONCURRENCY=8
时在 26 秒内执行 8 个线程,在CONCURRENCY=1
时在 4 秒内执行 1 个线程。 我不明白这个巨大的差距。
机器上没有其他东西在运行。 温度低,插电。
我可以确认我看到 8 个内核在使用中,我看到这个 Java 进程的 CPU 占用率为790%
。
这里的计算 function 只是一个虚拟计算,不是我使用的实际计算,而是重现问题的东西。
我希望程序将花费大致相同的时间,无论我使用多少线程(例如,只要CONCURRENCY <= 8
,并且我在 Apple M1 上有 10 个内核)。
然而,更多的线程需要更多的时间,并且它非常接近相同的性能(时间),就像我在一个内核上一个接一个地顺序执行计算 8 次一样。
事实上,我当然有不同的计算,这只是关于这个线程池使用的模式以及可能出错的地方。
将计算固定在核心上对此没有太大帮助。
i7 和 Apple M1 上的结果类型相同。
到目前为止,我只在 MBP 笔记本电脑上进行了测试。 在 Apple M1 上,由于即使在 1 个线程和 2 个线程之间也存在巨大差距,我认为热节流或功率节流不能发挥重要作用。
class ProblemWithParallelismTest {
private static final int CONCURRENCY = 8;
@SneakyThrows
@Test
void evaluate() {
var latch = new CountDownLatch(CONCURRENCY);
var executorService = newFixedThreadPool(CONCURRENCY);
for (int m = 0; m < CONCURRENCY; m++) {
executorService.submit(() -> {
computation();
latch.countDown();
});
}
latch.await();
}
private static void computation() {
long n = (long) Math.pow(10, 7);
var sum = 0;
for (long i = 0; i < n; i++) {
sum += LongStream.range(1, 9).boxed().limit(n).map(l -> new BigDecimal(String.valueOf(l))).distinct().count();
}
}
}
看起来,当我将计算固定到内核时,上面的内容确实如预期的那样在线程中水平扩展,并且时间从 1 个内核到 8 个内核是相同的。
这不会发生在原始计算上,但会发生在这个计算上。 我无法分享原始计算。
所以这证明节流不是原因。
原始计算确实占用了 790% 的 CPU(8 核),并且没有锁定问题。
在原始计算中,使用固定和所有,仍然
1 thread => 5s physical time
2 threads => 10s physical time
4 threads => 34s physical time
8 threads => 83s physical time
这是水平扩展的程序(从 1 个线程执行到 8 个线程的时间相同),带有虚拟计算:
final class PinnedThreadsParallelismTest {
private static final int CONCURRENCY = 8;
public static void main(String[] args) throws InterruptedException {
var latch = new CountDownLatch(CONCURRENCY);
var executorService = newFixedThreadPool(CONCURRENCY);
for (int m = 0; m < CONCURRENCY; m++) {
executorService.submit(() -> {
try (var lock = AffinityLock.acquireLock()) {
if (lock.cpuId() > 0) {
System.out.println("locked on " + lock.cpuId());
computation();
latch.countDown();
System.out.println("countDown");
} else {
latch.countDown();
}
}
});
}
latch.await();
System.exit(0);
}
private static void computation() {
long n = (long) Math.pow(10, 7);
var sum = 0;
for (long i = 0; i < n; i++) {
sum += LongStream.range(1, 9).boxed().limit(n).map(l -> new BigDecimal(String.valueOf(l))).distinct().count();
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.