通常而言,想给出任何关于何时该用并行流的定量建议都是不可能也毫无心义的,由于任何相似于“仅当至少有一千元素的时候才用并行流”的建议对于某台特定的机器上的特定操做多是对的,但在略有差别的另外一种状况下可能就大错特错了。尽管如此,咱们至少能够提出一些定性的意见,帮你决定某个特定的状况下是否有必要使用并行流。数据结构
若是有疑问,测量。把顺序流转换并行流垂手可得,但却不必定是好事。在某些状况下,并行流并不老是比顺序流快。此外,并行流和你的直觉不一致,因此在考虑选择顺序流仍是并行流时,第一也是最重要的建议就是使用合适的基准来检测其性能。ide
留意装箱。自动装箱和拆箱操做会大大下降性能。Java8中有原始类型流(IntStream、LongStream、DoubleStream)来避免这种操做,但凡是有可能都应该使用这些原始流。性能
有些操做自己在并行流上的性能就比顺序流差。特别是limit、findFirst等依赖于元素顺序的操做,它们在并行流上执行的代价很是大。例如,findAny会比findFirst性能好,由于它不必定要顺序来执行。你老是能够调用unordered方法来把顺序流变成无须流。那么,若是你须要流中的n个元素而不是专门的前n个的话,对无序并行流调用limit可能会比单个有序流(好比数据源是List)更高效。spa
还要考虑流的操做流水线的总计算成本。设N是要处理的元素的总数,Q是一个元素经过流水线的大体处理成本,则N*Q就是这个对成本的一个粗略的定型估计。Q值较高就意味着使用并行流时性能好的可能性比较大。hash
对于较小的数据量,选择并行流几乎历来不都是一个好的选择。并行处理少数几个元素的好处还抵不上并行化形成的额外开销。it
要考虑流背后的数据结构是否易于分解。例如,ArrayList的拆分效率比LinkedList高不少,由于前者用不着遍历就能够平均拆分,然后者则必须遍历。另外,用range工厂方法建立的原始类型流也能够快速分解。最后,你能够本身实现Spliterator来彻底掌握分解过程。table
流自身的特色,以及流水线中的中间操做修改流的方式,均可能会改变分解过程的性能。例如,一个SIZED流能够分红大小相等的两部分,这样每一个部分均可以比较高效地并行处理,但筛选操做可能丢弃的元素个数却没法预测,致使流自己的大小未知。class
还要考虑终端操做中合并步骤的代价是大是小(例如Collector中的combiner方法)。若是这一步代价很大,那么组合每一个子流产生的部分结果所付出的代价就可能会超出经过并行流获得的性能提高。效率
按照可分解性总结了一些流数据源适不适合于并行。List
源 | 可分解性 |
ArrayList | 极佳 |
LinkedList | 差 |
IntStream.range | 极佳 |
Stream.iterate | 差 |
hashSet | 好 |
TreeSet | 好 |
接下来我将写一个例子,来演示对并行流正确应用。