Java 如果可能,我是否应该始终使用并行流?

Java 如果可能,我是否应该始终使用并行流?,java,parallel-processing,java-8,java-stream,Java,Parallel Processing,Java 8,Java Stream,使用Java8和lambdas,可以很容易地将集合作为流进行迭代,也可以很容易地使用并行流。来自的两个示例,第二个使用parallelStream: myShapesCollection.stream() .filter(e -> e.getColor() == Color.RED) .forEach(e -> System.out.println(e.getName())); myShapesCollection.parallelStream() // <-

使用Java8和lambdas,可以很容易地将集合作为流进行迭代,也可以很容易地使用并行流。来自的两个示例,第二个使用parallelStream:

myShapesCollection.stream()
    .filter(e -> e.getColor() == Color.RED)
    .forEach(e -> System.out.println(e.getName()));

myShapesCollection.parallelStream() // <-- This one uses parallel
    .filter(e -> e.getColor() == Color.RED)
    .forEach(e -> System.out.println(e.getName()));
myShapeCollection.stream()
.filter(e->e.getColor()==Color.RED)
.forEach(e->System.out.println(e.getName());
myShapeCollection.parallelStream()//e.getColor()==Color.RED)
.forEach(e->System.out.println(e.getName());
只要我不在乎顺序,使用平行线是否总是有益的?有人会认为,在更多的内核上划分工作会更快

还有其他考虑吗?什么时候应该使用并行流,什么时候应该使用非并行流


(问这个问题是为了引发关于如何以及何时使用并行流的讨论,不是因为我认为始终使用并行流是一个好主意。)

与顺序流相比,并行流的开销要高得多。协调线程需要花费大量时间。默认情况下我会使用顺序流,如果

只考虑并行流。
  • 我有大量的项目要处理(或者每个项目的处理都需要时间并且是并行的)

  • 首先,我有一个性能问题

  • 我还没有在多线程环境中运行该进程(例如:在web容器中,如果我已经有许多请求要并行处理,那么在每个请求中添加额外的并行层可能会产生负面影响,而不是正面影响)

在您的示例中,性能将由对
System.out.println()
的同步访问驱动,而使此过程并行将不会产生任何影响,甚至会产生负面影响

此外,请记住并行流并不能神奇地解决所有同步问题。如果进程中使用的谓词和函数使用共享资源,则必须确保所有内容都是线程安全的。特别是,如果你平行进行,副作用是你真正需要担心的事情


在任何情况下,测量,不要猜测!只有测量才能告诉你平行度值不值得。

JB一针见血。我唯一可以补充的是,Java8不做纯并行处理,它做。是的,我写了这篇文章,我做F/J已经有三十年了,所以我确实理解这个问题。

流API的设计目的是让编写计算变得简单,而不是将计算的执行方式抽象出来,使得在顺序和并行之间的切换变得容易

然而,仅仅因为它简单,并不意味着它总是一个好主意,事实上,仅仅因为你可以,就把
.parallel()
放在所有地方是一个坏主意


首先,请注意,并行性除了在有更多内核可用时能够更快地执行之外没有其他好处。并行执行总是比顺序执行涉及更多的工作,因为除了解决问题,它还必须执行子任务的调度和协调。希望是通过在多个处理器之间分解工作,您能够更快地找到答案;这是否真的发生取决于很多因素,包括数据集的大小、对每个元素进行的计算量、计算的性质(具体来说,一个元素的处理是否与其他元素的处理相互作用?),可用处理器的数量,以及竞争这些处理器的其他任务的数量

此外,请注意,并行性还经常暴露出计算中的不确定性,而这种不确定性通常被顺序实现所隐藏;有时,这并不重要,或者可以通过约束所涉及的操作来缓解(即,缩减运算符必须是无状态和关联的。)

实际上,有时并行会加快计算速度,有时不会,有时甚至会减慢计算速度。最好先使用顺序执行进行开发,然后在需要时应用并行性

(A)您知道提高性能和

(B)它实际上将提供更高的性能

(A)是一个业务问题,而不是技术问题。如果您是一名性能专家,您通常能够查看代码并确定(B),但智能路径是测量。(而且,在你确信(A)(如果代码足够快,最好将你的大脑周期应用到其他地方)

最简单的并行性能模型是“NQ”模型,其中
N
是元素数,
Q
是每个元素的计算量。通常,在开始获得性能优势之前,您需要产品NQ超过某个阈值。对于低Q问题,如“将数字从
1
相加到
N
”,您通常会看到
N=1000
N=10000
之间的盈亏平衡。对于高Q问题,您将看到阈值较低时的盈亏平衡

但现实相当复杂。因此,在您获得experthood之前,首先确定顺序处理实际花费的时间,然后测量并行性是否有帮助。

我观看了Brian Goetz的其中一篇文章(Lambda表达式的Java语言架构师和规范负责人)。他详细解释了在进行并行化之前要考虑的4个要点:

拆分/分解成本
–有时拆分比只做工作更昂贵
任务分派/管理成本
–可以在将工作交给其他线程所需的时间内完成大量工作。
结果组合成本
–有时是com
N x Q > 10000
    Exception in thread "main" java.lang.OutOfMemoryError
        at ...
        at java.base/java.util.stream.IntPipeline.findFirst(IntPipeline.java:528)
        at InfiniteTest.main(InfiniteTest.java:24)
    Caused by: java.lang.OutOfMemoryError: Java heap space
        at java.base/java.util.stream.SpinedBuffer$OfInt.newArray(SpinedBuffer.java:750)
        at ...
public static void main(String[] args) {
    // let's count to 1 in parallel
    System.out.println(
            IntStream.range(1, 1000_000_000)
                    .parallel()
                    .skip(100)
                    .findFirst()
                    .getAsInt());
}