并行流与串行流

Ján*_*čan 17 java parallel-processing lambda java-8 java-stream

并行流可能会产生与Java 8中的串行流不同的结果吗?根据我的信息,并行流与串行流相同,除了分成多个子流.这是一个速度问题.完成对元素的所有操作,并在最后组合子流的结果.最后,在我看来,对于并行和串行流,操作的结果应该是相同的.所以我的问题是,这段代码可能会给我一个不同的结果吗?如果有可能,为什么会发生?

int[] i = {1, 2, 5, 10, 9, 7, 25, 24, 26, 34, 21, 23, 23, 25, 27, 852, 654, 25, 58};
Double serial = Arrays.stream(i).filter(si -> {
    return si > 5;
}).mapToDouble(Double::new).map(NewClass::add).reduce(Math::atan2).getAsDouble();

Double parallel = Arrays.stream(i).filter(si -> {
    return si > 5;
}).parallel().mapToDouble(Double::new).map(NewClass::add).reduce(Math::atan2).getAsDouble();

System.out.println("serial: " + serial);
System.out.println("parallel: " + parallel);
Run Code Online (Sandbox Code Playgroud)
public static double add(double i) {
    return i + 0.005;
}
Run Code Online (Sandbox Code Playgroud)

结果是:

serial: 3.6971567726175894E-23

parallel: 0.779264049587662
Run Code Online (Sandbox Code Playgroud)

And*_*eas 13

javadoc reduce()说:

使用关联累加函数执行此流的元素的减少,[...]累加器函数必须是关联函数.

"associative"这个词链接到这个java doc:

如果满足以下条件,则运算符或函数op是关联的:

 (a op b) op c == a op (b op c)
Run Code Online (Sandbox Code Playgroud)

如果我们将其扩展为四个术语,可以看出这对并行评估的重要性:

 a op b op c op d == (a op b) op (c op d)
Run Code Online (Sandbox Code Playgroud)

因此,我们可以与(c op d)并行地评估(a op b),然后在结果上调用op.

关联操作的示例包括数字加法,最小值和最大值以及字符串连接.

正如@PaulBoddington在评论中提到的那样,atan2它不是关联的,因此对缩减操作无效.


无关

您的流序列有点偏.您应该并行操作之后进行过滤,可以缩短lambda,并且不应该对double进行包装:

double parallel = Arrays.stream(i)
                        .parallel()           // <-- before filter
                        .filter(si -> si > 5) // <-- shorter
                        .asDoubleStream()     // <-- not boxing
                        .reduce(Math::atan2)
                        .getAsDouble();
Run Code Online (Sandbox Code Playgroud)

  • 不相关的部分完全不相关.`.parallel()`可能位于管道的任何位置,结果也是一样的. (7认同)