gpt4 book ai didi

java - Java 8 流中的一个简单的 list.parallelStream() 似乎无法窃取工作?

转载 作者:搜寻专家 更新时间:2023-11-01 03:31:45 24 4
gpt4 key购买 nike

从这个问题“ Will inner parallel streams be processed fully in parallel before considering parallelizing outer stream? “,我知道流执行工作窃取。但是,我注意到它似乎经常不会发生。例如,如果我有一个包含 100,000 个元素的列表,并且我尝试以 parallelStream() 方式处理它, 我经常注意到我的大部分 CPU 核心都在“等待”状态下闲置。(注意:在列表中的 100,000 个元素中,一些元素需要很长时间才能处理,而另一些则很快;并且,这个列表是不平衡的,这就是为什么有些线程可能会“倒霉”并且有很多事情要做,而其他线程则很幸运并且没有什么可做的原因。

因此,我的理论是 JIT 编译器将 100,000 个元素初始划分为 16 个线程(因为我有 16 个内核),但随后在每个线程中,它只执行一个简单的(顺序的)for 循环(如这将是最有效的),因此永远不会发生工作窃取(这就是我所看到的)。

我认为原因Will inner parallel streams be processed fully in parallel before considering parallelizing outer stream?表明工作窃取是有一个正在流式传输的外部循环一个正在流式传输的内部循环,因此在这种情况下,每个内部循环都在运行时进行评估,并会创建新的任务,这些任务可以,在运行时,分配给“空闲”线程。想法?我做错了什么会“强制”一个简单的 list.parallelStream() 使用工作窃取吗? (我目前的解决方法是尝试根据各种试探法来平衡列表,以便每个线程通常看到相同数量的工作;但是,很难预测......)

最佳答案

这与 JIT 编译器无关,而与 Stream API 的实现有关。它将工作负载分成 block ,由工作线程按顺序处理。一般策略是拥有比工作线程更多的作业以启用工作窃取,例如参见 ForkJoinTask.getSurplusQueuedTaskCount() ,可用于实现这种自适应策略。

以下代码可用于检测当源为 ArrayList 时有多少元素被顺序处理:

List<Object> list = new ArrayList<>(Collections.nCopies(10_000, ""));
System.out.println(System.getProperty("java.version"));
System.out.println(Runtime.getRuntime().availableProcessors());
System.out.println( list.parallelStream()
.collect(
() -> new ArrayList<>(Collections.singleton(0)),
(l,x) -> l.replaceAll(i -> i + 1),
List::addAll) );

在我当前的测试机器上,它打印:

1.8.0_60
4
[625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625]

因此 block 多于核心,以允许窃取工作。但是,一旦 block 的顺序处理开始,它就无法进一步拆分,因此当每个元素的执行时间差异很大时,此实现具有局限性。这始终是一种权衡。

关于java - Java 8 流中的一个简单的 list.parallelStream() 似乎无法窃取工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50283041/

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