当在同一流管道中使用的终端操作不遵守顺序时,中间操作是否遵守顺序?

时间:2019-04-14 13:48:42

标签: java java-8 java-stream

如果我在forEach()终端操作的流管道中使用map操作(无论其顺序流还是并行流,它都不遵守遇到顺序)(作为源),将按照遇到顺序进行映射顺序流或并行流时列表的哪个?

List<Integer> = Arrays.asList(1,2,3,4,5)
someList.stream().map(i -> i*2).forEach(System.out::println) // this is sequential stream
someList.parallelStream().map(i -> i*2).forEach(System.out::println) // this is parallel stream

如果是,那么在本帖子https://stackoverflow.com/a/47337690/5527839中,提到将并行执行映射操作。如果保持顺序,那么在使用并行流时如何使性能更好。使用并行流有什么意义?

2 个答案:

答案 0 :(得分:2)

如果保持顺序,那么在使用并行流时如何使性能更好。 (使用并行流有什么意义?(是,您仍然可以获得性能,但没有达到预期的水平))

即使在forEachOrdered()期间使用parallelStream,中间操作map也会由并发线程执行,但是在终端操作orEachOrdered中,它们会按顺序进行处理。试试下面的代码,您将在map操作中看到并行性

List<Integer> someList = Arrays.asList(1,2,3,4,5);
            someList.stream().map(i -> {
                System.out.println(Thread.currentThread().getName()+" Normal Stream : "+i);
                return i*2;
            }).forEach(System.out::println); // this is sequential stream

            System.out.println("this is parallel stream");

            someList.parallelStream().map(i -> {
                System.out.println(Thread.currentThread().getName()+" Parallel Stream : "+i);
                return i*2;
            }).forEachOrdered(System.out::println); // this is parallel stream

地图荣誉遭遇顺序?订购是否与中间操作有关?

如果是parallelstream,则映射将不会遇到任何顺序;如果是正常流,则映射将按顺序遇到,这完全取决于流,而不取决于中间操作

答案 1 :(得分:1)

尽管许多中间操作确实保留了排序,而不必明确指定该需求,但我总是更喜欢假设流经java流api的数据即使在给出相同代码的情况下也不会保证在每种情况下都是有序的。

当必须保留元素的顺序时,将终端操作指定为有序操作就足够了,并且数据在输出时将是有序的。就您而言,我相信您会寻找

.forEachOrdered()

  

如果订单保持不变,那么在什么情况下它将如何改善性能   使用并行流。使用并行流有什么意义?

我已经听到了很多意见。我相信,只有在流水线内进行少量处理时,才应使用并行流,否则与串行流相比,管理并行流的开销在大多数情况下会降低性能。如果您要进行一些密集的处理,那么即使指示保留顺序,并行操作仍肯定会比串行操作快,因为毕竟,要处理的数据都以任何一种方式存储在堆中,并且指向该数据的指针是有序的,从管道的末端穿过。流排序所需要做的全部工作就是按照遇到指针的顺序来分发指针,但是它可以并行处理数据,并等待队列前面的数据还没有完成。

我敢肯定这有点过分简化,因为在某些情况下,有序流将要求数据从一个元素共享到另一个元素(例如收集器),但是基本概念是有效的,因为即使在在这种情况下,并行流一次可以处理至少两个数据。