为什么 peek 不以并行流运行?

问题描述 投票:0回答:1

以下是我的代码片段,结果总是显示:

main sort3
main sort3
main sort3
main sort3

peek
之后的
sorted
似乎没有运行。你遇到过这种奇怪的事情吗?

public static void main(String[] args) throws InterruptedException {
    Random random = new Random();

    Stream<Integer> parallel = Stream.generate(() -> random.nextInt(1000))   
            .limit(10)    

            .sorted((a, b) -> {
                System.out.println(Thread.currentThread().getName() + " sort3 ");
                return a.compareTo(b);
            })                 //3
            .peek(i -> System.out.println(Thread.currentThread().getName() + " peek4 " + i))  //4
            .peek(i-> System.out.println(Thread.currentThread().getName()+" peek5 " + i))   //5
            .parallel().count();

    Thread.sleep(20000);

}
java parallel-processing java-stream
1个回答
0
投票

流上的

peek
方法不能保证被调用,即使存在元素也是如此。 特别是,当流能够优化临时操作时,例如在已知大小的流上调用
count
时,可能不会调用它。

在这种情况下,

sort
操作处理流的所有元素,并产生包含 10 个元素的流。 流实现能够确定最终计数操作的值为 10,而无需执行临时
peek
操作。 因此,它跳过
peek
调用作为优化。

在我的 Java 版本中,此方法的并行版本调用

peek
,但顺序版本则不会。 顺序版本的实现跳过调用
peek
或并行版本调用它也是正确的。 最终,是否在特定情况下调用
peek
取决于实现。 因此,依靠
peek
来保证程序正确性通常是一个坏主意,而仅将其用于调试流管道的既定目的。

文档

此类

peek
/
count
场景在
peek
count
文档中都有描述。

peek

API说明:

此方法的存在主要是为了支持调试,您希望在元素流过管道中的某个点时查看元素:

[…]

在流实现能够优化部分或全部元素的生产的情况下(例如使用像

findFirst
这样的短路操作,或者在
count()
中描述的示例),该操作将不会为这些元素调用。

count

API说明:

如果实现能够直接从流源计算计数,则可以选择不执行流管道(顺序或并行)。在这种情况下,不会遍历任何源元素,也不会评估任何中间操作。具有副作用的行为参数可能会受到影响,除了调试等无害情况外,强烈建议不要这样做。例如,考虑以下流:

List<String> l = Arrays.asList("A", "B", "C", "D");
long count = l.stream().peek(System.out::println).count();

流源

List
覆盖的元素数量是已知的,并且中间操作
peek
不会向流中注入或删除元素(可能是
flatMap
filter 的情况) 
操作)。因此,计数是
List
的大小,无需执行管道,并且作为副作用,打印出列表元素。

© www.soinside.com 2019 - 2024. All rights reserved.