差異處
這裏顯示兩個版本的差異處。
Both sides previous revision 前次修改 下次修改 | 前次修改 | ||
java:effective_java:lambdas_and_streams:use_caution_when_making_streams_parallel [2019/07/20 23:23] 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> | ||
行 8: | 行 8: | ||
</code> | </code> | ||
但這個item要強調的是: 千萬別亂用!! (以下內容我結合Java 8 Lambdas技術手冊做補充) | 但這個item要強調的是: 千萬別亂用!! (以下內容我結合Java 8 Lambdas技術手冊做補充) | ||
- | ==== Suitable Structure ==== | + | ===== Structure ===== |
- | 能獲得較佳效能的結構有ArrayList、HashMap、HashSet、ConcurrentHashMap、arrays、int ranges與long ranges。這是由於它們的結構能夠容易被切割。 | + | ==== Good ==== |
- | ==== Suitable Operations ==== | + | 能獲得較佳效能的結構有ArrayList、HashMap、HashSet、ConcurrentHashMap、arrays、int ranges與long ranges。這是由於它們的結構能夠容易被切割。書中還有提到Prefer SplittableRandom than ThreadLocalRandom,但這部分我沒使用過,無法做深入說明。 |
- | 能獲得較佳效能的terminal operations包含reduce、min、max、count與sum;short-circuiting operations包含anyMatch、allMatch與noneMatch。(short-circuiting operations代表著滿足部分條件就可以停止繼續做下去,中文為短路操作,詳細範例可以參考[[https://www.logicbig.com/tutorials/core-java-tutorial/java-util-stream/short-circuiting.html|link]]) | + | ==== Bad ==== |
- | ==== Unsuitable Operations ==== | + | 這通常是無法容易被切割的結構,像是LinkedList,我就有遇過同事使用LinkedList做parallel();再來就是使用Stream.iterate與BufferedReader.lines所產生的stream,因為初始長度未知。\\ |
- | 首先提到不適用的情況是使用Stream.iterate所產生的stream或者是透過limit處理的steam。這是由於預設的並行化流程並無法精準的知道該怎麼正確處理limit的邏輯。 | + | \\ |
- | ==== Others ==== | + | 另外容易被忽略的就是boxing和un-boxing轉換的效能問題,如果可以要盡量減少auto-boxing的操作,如此[[https://valueaddedprogramming.com/2017/09/18/optimizing-streams-autoboxing/|link]]所示。 |
- | - collect則不適合用在parallel的情況中,因為組合集合開銷非常大。 | + | ===== Operations ===== |
- | - Prefer SplittableRandom than ThreadLocalRandom. (這個我還沒使用過,無法深入說明) | + | ==== Good ==== |
- | ==== Conclusion & My Opinion ==== | + | 能獲得較佳效能的terminal operations包含reduce、min、max、count與sum;short-circuiting operations包含anyMatch、allMatch與noneMatch。(short-circuiting operations代表著滿足部分條件就可以停止繼續做下去,中文為短路操作,詳細範例可以參考[[https://www.logicbig.com/tutorials/core-java-tutorial/java-util-stream/short-circuiting.html|link]])\\ |
+ | \\ | ||
+ | 除此之外,還有一個重點就是操作是否有狀態,有狀態就會有維持狀的成本與限制;無狀態操作包含map、filter與flatMap。 | ||
+ | ==== Bad ==== | ||
+ | 有狀態操作包含了sorted、distinct與limit。其中limit在effective java中是特別被列為不適用,這是由於預設的並行化流程並無法精準的知道該怎麼正確處理limit的邏輯。\\ | ||
+ | \\ | ||
+ | collect也不適合用在parallel的情況中,因為組合集合開銷非常大;我們大都使用parallel在物件的轉換上,此時**資料量**會是決定你效能的一個因素。 | ||
+ | ===== Pool size ===== | ||
+ | 根據[[https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html|Java 8 Doc]],預設的parallelism為處理器核心處量。假如這個值設太大,會導致大量的context switch。 | ||
+ | ===== 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 |