Java 并行流中的流操作等待直到上一个流操作处理完所有元素
我想知道并行流的流管道中的流操作是否会等待前一个流操作完成所有流元素的处理 如果我有以下流管道:Java 并行流中的流操作等待直到上一个流操作处理完所有元素,java,java-8,parallel-processing,java-stream,Java,Java 8,Parallel Processing,Java Stream,我想知道并行流的流管道中的流操作是否会等待前一个流操作完成所有流元素的处理 如果我有以下流管道: List parsedNumbers=IntStream.range(1,6) .parallel() .map(字符串::valueOf) .map(整型字符串=>{ System.out.println(“第一个打印语句:“+integerastring”); 返回整数字符串; }) .map(整型字符串=>{ System.out.println(“第二个打印语句:“+integerastri
List parsedNumbers=IntStream.range(1,6)
.parallel()
.map(字符串::valueOf)
.map(整型字符串=>{
System.out.println(“第一个打印语句:“+integerastring”);
返回整数字符串;
})
.map(整型字符串=>{
System.out.println(“第二个打印语句:“+integerastring”);
返回整数字符串;
})
.collect(Collectors.toList());
是否可能已经为元素X调用了System.out.println(“第一个打印语句:“+integerastring”)
,但仍在为流中的另一个元素Y执行String::parseInt
操作
该代码的输出是否可以如下所示:
首次打印声明:1首次打印声明:2
首次打印声明:3
第二份打印报表:1
第二份打印报表:2
首次打印声明:4
第二份打印报表:3
第二份打印报表:4
首次打印声明:5
第二份打印报表:5份 当然,它将永远是这样的: 首次打印声明:1
首次打印声明:2
首次打印声明:3
首次打印声明:4
首次打印声明:5
第二份打印报表:1
第二份打印报表:2
第二份打印报表:3
第二份打印报表:4
第二份打印报表:5份
是的,可以<代码>中间阶段可以以任何顺序执行,
终端
操作有一个定义的顺序,如果流的源有一个顺序(例如,与集合
不同),并且流本身不改变该顺序(调用无序
,尽管目前这没有多大作用)
也就是说:您不知道在给定的时间点上哪个元素将流经其中一个阶段,对于并行流,没有处理元素的顺序
更大的问题是你为什么在乎?中间操作应该是没有副作用的,依赖任何顺序都不是好主意 不保证处理顺序,即使是顺序流也是如此。只有最终结果与遭遇顺序一致(如果数据有) 当您运行以下顺序代码时
List<String> parsedNumbers = IntStream.range(1, 6)
.mapToObj(String::valueOf)
.map(integerAsString -> {
System.out.println("First print statement: " + integerAsString);
return integerAsString;
})
.map(integerAsString -> {
System.out.println("Second print statement: " + integerAsString);
return integerAsString;
})
.collect(Collectors.toList());
显示流并不像您期望的那样工作。参考实现显然倾向于在处理下一个元素之前将每个元素传递给整个流。当您启用并行处理时,将在每个CPU内核上执行相同的处理逻辑
所以当我使用
List<String> parsedNumbers = IntStream.range(1, 6)
.parallel()
.mapToObj(String::valueOf)
.map(integerAsString -> {
System.out.println("First print statement: " + integerAsString);
return integerAsString;
})
.map(integerAsString -> {
System.out.println("Second print statement: " + integerAsString);
return integerAsString;
})
.collect(Collectors.toList());
这可能看起来像是在第二个print语句之前将第一个print语句作为一个阶段进行处理,但这只是一个巧合,它拥有比流元素更多的CPU核,而且是一个幸运的定时。例如,当我将范围(1,6)
更改为范围(1,18)
时,我得到如下结果
第一次打印语句:6
首次打印声明:10
首次打印声明:9
首次打印声明:3
首次打印声明:15
首次打印声明:5
第二份打印报表:9
首次打印声明:11
首次打印声明:8
第二份打印报表:3份
第二份打印报表:11
第二份打印报表:5份
第二份打印报表:10份
第二份打印报表:6份
首次打印报表:7
首次打印声明:12
第二份打印报表:8份
第二份打印报表:15份
第二份打印报表:12份
第二份打印报表:7份
第一份打印报表:2份
首次打印声明:17
首次打印声明:14
首次打印声明:4
第二份打印声明:14
第二份打印报表:17
第二份打印报表:2份
首次打印声明:1
首次打印声明:16
首次打印报表:13
第二份打印报表:16
第二份打印报表:1
第二份打印报表:4份
第二份打印报表:13
不仅不能保证处理顺序,也不能保证将处理哪些元素,例如
IntStream.range(1, 30)
.filter(i -> i%13 == 1)
.peek(i -> System.out.println("processing "+i))
.parallel()
.findFirst()
.ifPresent(i -> System.out.println("result is "+i));
在我的设置中生成
处理14
处理1
处理27
结果是1
因此,虽然结果被保证为
1
,是遭遇战顺序中的第一个匹配元素,但不能保证其他元素(按照遭遇战顺序)不会被处理。为什么这是相关的<代码>流s应该没有副作用,所以人们不应该在意。副作用是不鼓励的,但不是禁止的。不过,我同意。我只是想知道前几天的排序。这些操作在连续的流中甚至不以这种方式工作。除此之外,.map(String::parseInt)
毫无意义。将int
转换为String
不是解析,因此不存在这样的方法。parseInt
确实不存在,我的错。我更新了代码以使用正确的方法。不鼓励但不禁止出现副作用。不过,我同意。“我只是想知道前几天的订货情况。”泰图伦说得对,我所知道的最著名的副作用是明显的。