gpt4 book ai didi

java - 并行 flatMap 总是顺序的

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:17:02 27 4
gpt4 key购买 nike

假设我有这段代码:

 Collections.singletonList(10)
.parallelStream() // .stream() - nothing changes
.flatMap(x -> Stream.iterate(0, i -> i + 1)
.limit(x)
.parallel()
.peek(m -> {
System.out.println(Thread.currentThread().getName());
}))
.collect(Collectors.toSet());

输出是相同的线程名称,因此此处并行 没有任何好处 - 我的意思是只有一个线程完成所有工作。

flatMap 里面有这样的代码:

result.sequential().forEach(downstream);

我理解如果“外部”流是并行的(它们可能会阻塞),则强制使用 sequential 属性,“外部”将不得不等待“flatMap”完成,反之亦然(因为使用了相同的公共(public)池)但是为什么总是强制这样做?

这是可以在以后的版本中改变的事情之一吗?

最佳答案

有两个不同的方面。

首先,只有一个管道,它是顺序的或并行的。在内部流中选择顺序还是并行是无关紧要的。请注意,您在引用的代码片段中看到的 downstream 消费者代表整个后续流管道,因此在您的代码中,以 .collect(Collectors.toSet()); 结尾,这个消费者最终会将结果元素添加到一个非线程安全的 Set 实例中。因此,与单个消费者并行处理内部流会破坏整个操作。

如果外部流被拆分,引用的代码可能会被同时调用,同时不同的消费者添加到不同的集合。这些调用中的每一个都会处理映射到不同内部流实例的外部流的不同元素。由于您的外部流仅包含单个元素,因此无法拆分。

顺便,这个已经实现了,也是Why filter() after flatMap() is “not completely” lazy in Java streams?的原因问题,因为在内部流上调用 forEach 会将所有元素传递给下游消费者。如 this answer 所示,支持懒惰和子流拆分的替代实现是可能的。但这是一种根本不同的实现方式。 Stream 实现的当前设计主要由消费者组成,因此最终,源拆分器(以及从中分离出来的那些)接收一个 Consumer 代表 tryAdvance 中的整个流管道forEachRemaining。相反,链接答案的解决方案进行拆分器组合,生成一个新的 Spliterator 委托(delegate)给源拆分器。我想,这两种方法各有优势,但我不确定,如果反过来,OpenJDK 实现会损失多少。

关于java - 并行 flatMap 总是顺序的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45038120/

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