差異處

這裏顯示兩個版本的差異處。

連向這個比對檢視

Both sides previous revision 前次修改
下次修改
前次修改
java:effective_java:lambdas_and_streams:use_caution_when_making_streams_parallel [2019/07/21 00:01]
tony
java:effective_java:lambdas_and_streams:use_caution_when_making_streams_parallel [2023/06/25 09:48] (目前版本)
行 1: 行 1:
 {{tag>​java effective_java}} {{tag>​java effective_java}}
 ====== Effective Java - Use caution when making streams parallel ====== ====== Effective Java - Use caution when making streams parallel ======
-===== Introduction ​& My Opinion ​=====+===== Introduction =====
 在Java 8中,你只要用以下寫法,很容易就可以讓你的工作並行化:​ 在Java 8中,你只要用以下寫法,很容易就可以讓你的工作並行化:​
 <code java> <code java>
行 10: 行 10:
 ===== Structure ===== ===== Structure =====
 ==== Good ==== ==== Good ====
-能獲得較佳效能的結構有ArrayList、HashMap、HashSet、ConcurrentHashMap、arrays、int ranges與long ranges。這是由於它們的結構能夠容易被切割。+能獲得較佳效能的結構有ArrayList、HashMap、HashSet、ConcurrentHashMap、arrays、int ranges與long ranges。這是由於它們的結構能夠容易被切割。書中還有提到Prefer SplittableRandom than ThreadLocalRandom,但這部分我沒使用過,無法做深入說明
 ==== Bad ==== ==== Bad ====
-這通常是無法容易被切割的結構,像是LinkedList,我就有遇過同事使用LinkedList做parallel();再來就是使用Stream.iterate與BufferedReader.lines所產生的stream,因為初始長度未知。+這通常是無法容易被切割的結構,像是LinkedList,我就有遇過同事使用LinkedList做parallel();再來就是使用Stream.iterate與BufferedReader.lines所產生的stream,因為初始長度未知。\\ 
 +\\ 
 +另外容易被忽略的就是boxing和un-boxing轉換的效能問題,如果可以要盡量減少auto-boxing的操作,如此[[https://​valueaddedprogramming.com/​2017/​09/​18/​optimizing-streams-autoboxing/​|link]]所示
 ===== Operations ===== ===== Operations =====
 ==== Good ==== ==== Good ====
行 19: 行 21:
 除此之外,還有一個重點就是操作是否有狀態,有狀態就會有維持狀的成本與限制;無狀態操作包含map、filter與flatMap。 除此之外,還有一個重點就是操作是否有狀態,有狀態就會有維持狀的成本與限制;無狀態操作包含map、filter與flatMap。
 ==== Bad ==== ==== Bad ====
-有狀態操作包含了sorted、distinct與limit。其中limit在effective java中是特別被列為不適用,這是由於預設的並行化流程並無法精準的知道該怎麼正確處理limit的邏輯。 +有狀態操作包含了sorted、distinct與limit。其中limit在effective java中是特別被列為不適用,這是由於預設的並行化流程並無法精準的知道該怎麼正確處理limit的邏輯。\\ 
-===== Others ===== +\\ 
-  ​- ​collect不適合用在parallel的情況中,因為組合集合開銷非常大。 +collect不適合用在parallel的情況中,因為組合集合開銷非常大;我們大都使用parallel在物件的轉換上,此時**資料量**會是決定你效能的一個因素。 
-  - Prefer SplittableRandom than ThreadLocalRandom(這個我還沒使用過無法深入說明)+===== Pool size ===== 
 +根據[[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​util/​concurrent/​ForkJoinPool.html|Java 8 Doc]],預設的parallelism為處理器核心處量。假如這個值設太大會導致大量的context switch。
 ===== Conclusion & My Opinion ===== ===== Conclusion & My Opinion =====
   - 這個item的結論是:​ 「你要有理由或者測試去證明使用parallel會加快速度,否則代價就是性能災難或是功能直接出問題」。   - 這個item的結論是:​ 「你要有理由或者測試去證明使用parallel會加快速度,否則代價就是性能災難或是功能直接出問題」。
   - 以我們的經驗來說,由於parallel()預設使用common的ForkJoinPool,因此建議使用在cpu-bound且不會blocking的工作,否則可能會引起dead-lock的問題。   - 以我們的經驗來說,由於parallel()預設使用common的ForkJoinPool,因此建議使用在cpu-bound且不會blocking的工作,否則可能會引起dead-lock的問題。
-  ​- 前文有提到collect並不適合用在parallel的情況,但事實上我們最常用在物件的轉換;因此**資料量**會是決定你效能的一個因素。 +  - 資料結構、資料量、boxing/​un-boxing、pool size、工作分解與合併都會影響到效能。
-  ​- 資料結構、boxing/​un-boxing、pool size、工作分解與合併都會影響到效能。+
 ===== Note ===== ===== Note =====
-Effective Java第三版Item 48。+  - Effective Java第三版Item 48。 
 +  - 有一種用來簡單判斷是否要用parallel stream的NQ Model,可參考[[http://​gee.cs.oswego.edu/​dl/​html/​StreamParallelGuidance.html|link]]。N為item數量,Q為function的工作量(也可用幾行程式碼來替代),N*Q至少要>​=10000時,parallel才有可能會優於sequential;但根據這個[[https://​www.youtube.com/​watch?​v=x5akmCWgGY0|演講]]內容提到,如果Q是i+=1這種操作,會由於CPU處理速度已太快的原因,即使N的數量有一百萬也不見得比較好
 ===== Reference ===== ===== Reference =====
   * Effective Java, 3/e   * Effective Java, 3/e