通常而言,想給出任何關於何時該用並行流的定量建議都是不可能也毫無心義的,由於任何相似於「僅當至少有一千元素的時候才用並行流」的建議對於某臺特定的機器上的特定操做多是對的,但在略有差別的另外一種狀況下可能就大錯特錯了。儘管如此,咱們至少能夠提出一些定性的意見,幫你決定某個特定的狀況下是否有必要使用並行流。數據結構
若是有疑問,測量。把順序流轉換並行流垂手可得,但卻不必定是好事。在某些狀況下,並行流並不老是比順序流快。此外,並行流和你的直覺不一致,因此在考慮選擇順序流仍是並行流時,第一也是最重要的建議就是使用合適的基準來檢測其性能。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 | 好 |
接下來我將寫一個例子,來演示對並行流正確應用。