首页 文章

我应该尽可能使用并行流吗?

提问于
浏览
350

使用Java 8和lambdas,可以很容易地将集合作为流进行迭代,同样易于使用并行流 . 来自the docs的两个示例,第二个使用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()));

只要我不关心顺序,使用并行是否总是有益的?人们会认为将更多内核的工作划分得更快 .

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

(这个问题被要求引发关于如何以及何时使用并行流的讨论,而不是因为我认为总是使用它们是一个好主意 . )

4 回答

  • 42

    与顺序流相比,并行流具有更高的开销 . 协调线程需要花费大量时间 . 我默认使用顺序流,只考虑并行流

    • 我有大量要处理的项目(或者每个项目的处理需要时间并且可以并行化)

    • 我首先遇到了性能问题

    • 我还没有在多线程环境中运行该进程(例如:在Web容器中,如果我已经有很多并行处理的请求,在每个请求中添加一个额外的并行层可能会比正面更多负面效果)

    在您的示例中,无论如何,性能将由对 System.out.println() 的同步访问驱动,并且使该过程并行将不起作用,甚至是否定的 .

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

    无论如何,衡量,不要猜!只有测量才能告诉您并行性是否值得 .

  • 522

    Stream API旨在使编写计算变得容易,这些计算方式与执行方式相反,使得顺序和并行之间的切换变得容易 .

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

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

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

    实际上,有时并行性会加速你的计算,有时它不会,有时它甚至会减慢它的速度 . 最好先使用顺序执行开发,然后应用并行性,其中(A)您知道实际上有益于提高性能,(B)它实际上会提高性能 . (A)是业务问题,而不是技术问题 . 如果您是性能专家,您通常可以查看代码并确定(B),但智能路径是衡量 . (而且,在你确信(A)之前不要打扰;如果代码足够快,最好在其他地方应用你的大脑周期 . )

    最简单的并行性能模型是“NQ”模型,其中N是元素的数量,Q是每个元素的计算 . 通常,在开始获得性能优势之前,您需要产品NQ超过某个阈值 . 对于像“将数字从1加到N”这样的低Q问题,您通常会看到N = 1000和N = 10000之间的盈亏 balancer . 对于Q值较高的问题,您会看到在较低阈值处出现断层现象 .

    但现实非常复杂 . 因此,在您获得专业知识之前,首先确定顺序处理实际上是否会使您付出代价,然后衡量并行性是否会有所帮助 .

  • 183

    我观看了presentations的一个 Brian Goetz (Lambda Expressions的Java语言架构师和规范主管) . 他在进行并行化之前详细解释了以下4个要点:

    Splitting / decomposition costs

    • 有时分裂比仅仅做工作更昂贵!
      Task dispatch / management costs
    • 可以做很多事在将工作交给另一个线程所花费的时间 .
      Result combination costs
    • 有时组合涉及复制大量数据 . 例如,添加数字很便宜,而合并集很昂贵 .
      Locality
    • 房间里的大象 . 这是每个人都可能错过的重点 . 您应该考虑缓存未命中,如果CPU由于缓存未命中而等待数据,那么您将无法理解基于数组的源并行化最佳,因为下一个索引(在当前索引附近)被缓存并且CPU将遇到的机会更少缓存未命中 .

    他还提到了一个相对简单的公式来确定并行加速的可能性 .

    NQ Model

    N x Q > 10000
    

    哪里,
    N =数据项的数量
    Q =每件商品的工作量

  • 12

    JB击中头部 . 我唯一可以添加的是Java8不进行纯并行处理,它确实paraquential是的我写了这篇文章而且我已经做了三十年的F / J所以我确实理解了这个问题 .

相关问题