我是否应该尽可能使用并行stream?
使用Java 8和lambdaexpression式,可以很容易地将集合作为stream进行迭代,并且使用并行stream也很容易。 来自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()));
只要我不关心顺序,使用并行总是有益的。 人们可能会认为将更多内核的工作划分得更快。
还有其他的考虑吗? 什么时候应该使用并行stream,何时应该使用非并行stream?
(这个问题被要求引发关于如何和何时使用并行stream的讨论,不是因为我认为总是使用它们是一个好主意。)
与顺序stream相比,并行stream具有更高的开销。 协调线程需要大量的时间。 我会默认使用顺序stream,只考虑并行stream
-
我有大量的项目要处理(或每个项目的处理需要时间和可并行化)
-
首先,我有一个性能问题
-
我还没有在multithreading环境中运行这个进程(例如:在一个Web容器中,如果我已经有很多并行处理的请求,那么在每个请求中增加一个额外的并行层可能会比正面的效果更负面)
在你的例子中,性能无论如何都是由对System.out.println()
的同步访问所驱动的,而使这个过程并行将不起作用,甚至是负面的。
此外,请记住,并行stream不会奇迹般地解决所有的同步问题。 如果过程中使用的谓词和函数使用共享资源,则必须确保所有内容都是线程安全的。 尤其是,如果你平行的话,副作用就是你必须担心的事情。
无论如何,措施,不要猜测! 只有一个度量才能告诉你这个并行是否值得。
Stream API的devise是为了使编写计算的过程变得简单,从而避免执行它们,从而使顺序和并行之间的切换变得简单。
然而,仅仅因为它容易,并不意味着它永远是一个好主意,事实上,只是因为可以,所以放弃.parallel()
是一个糟糕的主意。
首先,请注意,并行性除了在有更多内核可用时执行速度更快之外,没有其他优势。 并行执行总是需要比顺序执行更多的工作,因为除了解决问题之外,还必须执行分派和协调子任务。 希望通过分解多个处理器的工作,能够更快地得到答案。 这是否真的发生取决于很多事情,包括你的数据集的大小,你在每个元素上做了多less计算,计算的本质(具体来说,一个元素的处理是否与其他处理相互作用?) ,可用的处理器数量以及竞争这些处理器的其他任务的数量。
此外,注意到并行也经常将非确定性注入到计算中; 有时这并不重要,或者可以通过限制所涉及的操作来减轻(即,减less操作符必须是无状态和联想的)。
实际上,有时候并行会加快你的计算速度,有时候不会,有时甚至会减慢速度。 (A)你知道增加性能实际上是有益的,(B)它实际上会提高性能,所以最好先开发顺序执行,然后再应用并行。 (A)是一个业务问题,而不是技术问题。 如果你是一名绩效专家,你通常可以查看代码并确定(B),但是智能path是衡量的。 (而且,除非你确信(A),否则不要麻烦;如果代码速度够快,最好在其他地方应用你的大脑周期。)
并行性最简单的性能模型是“NQ”模型,其中N是元素的数量,Q是每个元素的计算。 一般来说,在开始获得绩效优势之前,您需要产品NQ超过某个阈值。 对于像“从1到N的数字加起来”这样的低Q问题,您通常会看到N = 1000和N = 10000之间的平衡。 Q值较高的问题,你会看到在较低的门槛breakevens。
但现实相当复杂。 所以,直到你达到专业水平,首先确定什么时候顺序处理实际上会花费你一些东西,然后衡量并行性是否会有所帮助。
我观看了Brian Goetz (Lambdaexpression式的Java语言架构师和规范负责人)的介绍之一 。 他在进行并行化之前详细解释以下四点:
分解/分解成本
– 有时候分裂比做工作更昂贵!
任务调度/pipe理成本
– 在将工作交给另一个线程所花费的时间可以做很多工作。
结果组合成本
– 有时组合涉及复制大量的数据。 例如,添加数字是便宜的,而合并集合是昂贵的。
局部性
– 房间里的大象 这是每个人都可能错过的重要的一点。 你应该考虑caching未命中,如果一个CPU由于caching未命中而等待数据,那么你将不会通过并行获得任何东西。 这就是为什么基于arrays的数据源在下一个索引(当前索引附近)被caching的情况下并行化的最佳时机,而且CPU会遇到caching未命中的机会较less。
他还提到了一个相对简单的公式来确定并行加速的机会。
NQ型号 :
N x Q > 10000
哪里,
N =数据项的数量
Q =每个项目的工作量
JB击中了头部。 我唯一可以补充的是,Java8不会做纯并行处理,它是顺序的。是的,我写了这篇文章,我已经做了三十年的F / J,所以我明白这个问题。