gpt4 book ai didi

java - 为什么 Stream Parallel() 不使用所有可用线程?

转载 作者:行者123 更新时间:2023-12-03 18:28:34 26 4
gpt4 key购买 nike

我尝试使用在具有 100 多个可用线程的自定义 ForkJoinPool 内提交的 Java8(1.8.0_172) stream.parallel() 并行运行 100 个 Sleep 任务。每个任务都会 hibernate 1 秒。鉴于 100 个 sleep 可以并行完成,我预计整个工作将在约 1 秒后完成。不过我观察到运行时间为 7 秒。

    @Test
public void testParallelStream() throws Exception {
final int REQUESTS = 100;
ForkJoinPool forkJoinPool = null;
try {
// new ForkJoinPool(256): same results for all tried values of REQUESTS
forkJoinPool = new ForkJoinPool(REQUESTS);
forkJoinPool.submit(() -> {

IntStream stream = IntStream.range(0, REQUESTS);
final List<String> result = stream.parallel().mapToObj(i -> {
try {
System.out.println("request " + i);
Thread.sleep(1000);
return Integer.toString(i);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).collect(Collectors.toList());
// assertThat(result).hasSize(REQUESTS);
}).join();
} finally {
if (forkJoinPool != null) {
forkJoinPool.shutdown();
}
}
}

输出指示在暂停 1 秒之前执行约 16 个流元素,然后执行另一个约 16 个流元素,依此类推。因此,即使 forkjoinpool 是用 100 个线程创建的,但也只有 ~16 个线程被使用。

一旦我使用超过 23 个线程,就会出现这种模式:

1-23 threads: ~1s
24-35 threads: ~2s
36-48 threads: ~3s
...
System.out.println(Runtime.getRuntime().availableProcessors());
// Output: 4

最佳答案

由于 Stream 实现对 Fork/Join 池的使用是一个实现细节,因此强制它使用不同的 Fork/Join 池的技巧也没有记录,并且似乎是偶然起作用的,即有一个 hardcoded constant根据默认池的并行度确定实际并行度。因此,最初并没有预见到使用不同的池。

但是,人们已经认识到,使用具有不适当目标并行性的不同池是一个错误,即使这个技巧没有记录在案,请参阅 JDK-8190974 .

它已在 Java 10 中修复,并向后移植到 Java 8,更新 222。

因此,一个简单的解决方案就是更新 Java 版本。

您还可以更改默认池的并行度,例如

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "100");

在进行任何 Fork/Join Activity 之前。

但这可能会对其他并行操作产生意想不到的影响。

关于java - 为什么 Stream Parallel() 不使用所有可用线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59841361/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com