java8流分组 性能_Java性能教程– Java 8流有多快?
java8流分組 性能
在此JAX Magazine的預覽預覽中,JAX倫敦發言人Angelika Langer為使用Java流的任何人回答了最重要的問題:它們真的更快嗎?
Java 8是JDK收集框架的主要補充,即流??API。 與集合相似,流表示元素序列。 集合支持對單個元素起作用的操作,例如add() , remove()和contains() 。 相反,流具有批量操作,例如forEach() , filter() , map()和reduce() ,它們訪問序列中的所有元素。 Java流的概念受到功能性編程語言的啟發,其中相應的抽象通常稱為序列,該序列也具有filter-map-reduce操作。 由于這種相似性,Java 8(至少在某種程度上)除了一直支持的面向對象范例之外,還允許一種功能性的編程風格。
也許與普遍的看法相反,Java編程語言的設計人員沒有擴展Java及其JDK來允許Java中的功能編程,也沒有將Java變成“目標與功能”混合編程語言。 發明Java流的實際動機是性能,或者更準確地說,是使并行性更易于軟件開發人員訪問(請參見Lambda州的Brian Goetz )。 考慮到硬件的發展方式,這個目標對我來說很有意義。 我們的硬件今天有數十個cpu內核,將來可能還會有數百個。 為了有效利用硬件功能,從而達到最新的執行性能,我們必須并行化。 畢竟–在多核平臺上運行單個線程有什么意義? 同時,多線程編程被認為是困難且容易出錯的,這是正確的。 流有兩種形式(順序流和并行流),旨在隱藏運行多個線程的復雜性。 并行流使魔術,毫不費力地以每個Java開發人員都可以訪問的方式并行執行批量操作變得極為容易。
并行流操作是否比順序操作快? 聽到Angelika Langer在2015年JAX倫敦上的演講。
因此,讓我們談談性能。 Java 8流有多快? 一個普遍的期望是流操作的并行執行比僅單個線程的順序執行要快。 是真的嗎 流會提高性能嗎?
為了回答有關性能的問題,我們必須進行衡量,即運行一個微基準測試。 標桿管理也很困難且容易出錯。 您需要執行適當的預熱,注意各種失真的影響,從虛擬機的JIT編譯器應用的優化(消除死代碼是臭名昭著的)到硬件優化(例如增加一個內核的cpu頻率),其他核心處于閑置狀態)。 通常,必須以一粒鹽作為基準結果。 每個基準都是實驗。 其結果取決于上下文。 永遠不要相信在您的硬件環境中尚未產生的基準數據。 這樣說,讓我們嘗試一下。
將流與循環進行比較
首先,我們想了解流的批量操作與常規的傳統for-比較。 首先出于性能考慮是否值得使用流?
我們將用于基準測試的序列是一個int-數組,其中填充了500,000個隨機整數值。 在此數組中,我們將搜索最大值。
這是帶有for-循環的傳統解決方案:
int[] a = ints; int e = ints.length; int m = Integer.MIN_VALUE; for(int i=0; i < e; i++) if(a[i] > m) m = a[i];這是使用順序IntStream的解決方案:
int m = Arrays.stream(ints).reduce(Integer.MIN_VALUE, Math::max);我們在具有適當預熱功能的過時硬件(雙核,無動態超頻)上進行了測量,并得出了中途可靠的基準數據。 這是在特定情況下的結果:
int-array, for-loop : 0.36 ms int-array, seq. stream: 5.35 ms結果令人震驚:舊的for-循環比順序流快15倍。 真令人失望! 多年的開發工作花費在為Java 8構建流上,然后進行此?!?!? 可是等等! 在得出流非常慢的結論之前,讓我們看看如果用ArrayList <Integer>替換int- array會發生什么。
這是for-循環:
int m = Integer.MIN_VALUE; for (int i : myList)if (i>m) m=i;這是基于流的解決方案:
int m = myList.stream().reduce(Integer.MIN_VALUE, Math::max);結果如下:
ArrayList, for-loop : 6.55 ms ArrayList, seq. stream: 8.33 ms同樣, for-循環比順序流操作要快,但是ArrayList上的差異不如在陣列上那么重要。
讓我們考慮一下。 為什么結果相差這么大? 有幾個方面需要考慮。
首先,訪問數組元素非常快。 這是基于索引的內存訪問,沒有任何開銷。 換句話說,這是簡單的底層存儲訪問。 另一方面,通過迭代器訪問集合中的元素(例如ArrayList),并且迭代器不可避免地增加了開銷。 另外,對集合元素進行裝箱和拆箱會產生開銷,而int數組則使用普通原始類型int。 本質上,對于該ArrayList測量通過迭代和拳擊開銷而對于INT-陣列附圖示出的優點是支配for-環路。
其次,我們是否曾認真地期望過流會比普通的for-loop更快? 編譯器在優化循環方面擁有40多年的經驗,虛擬機的JIT編譯器尤其適合以與我們的基準測試相同的步伐來優化陣列上的for-循環。 另一方面,流是Java的最新擴展,并且JIT編譯器(尚未)尚未對其執行任何特別復雜的優化。
第三,我們必須記住,一旦掌握了序列元素,我們就不會做太多事情。 我們花了很多精力來嘗試訪問元素,然后對它做得很少。 我們只比較兩個整數,在JIT編譯之后,它們幾乎不止一個匯編指令。 因此,我們的基準測試說明了元素訪問的成本–不一定是典型情況。 如果應用于序列中每個元素的功能是CPU密集型的,則性能指標將發生重大變化。 您會發現,如果功能受CPU的限制很大,則for循環流和順序流之間將不再有可測量的差異。
加入我們的倫敦JAX – Java和軟件創新者大會。 使用以下代碼可享受10%的折扣:MP_JCG10
從這個基準實驗得出的最終結論不是流總是比循環慢。 是的,流有時比循環慢,但它們也可以同樣快。 這取決于情況。 帶回家的要點是順序流不會比循環快。 如果使用順序流,則出于性能原因,請不要這樣做; 之所以這樣做,是因為您喜歡函數式編程風格。
那么,性能改進流是在哪里發明的呢? 到目前為止,我們僅將循環與流進行了比較。 并行化如何? 流的點是易于并行化,以實現更好的性能。
比較順序流與并行流
作為第二個實驗,我們想弄清楚順序流與并行流在性能方面的比較。 并行流操作是否比順序操作快?
我們使用填充500,000個整數值的同一int-數組。 這是順序流操作:
int m = Arrays.stream(ints).reduce(Integer.MIN_VALUE, Math::max);這是并行流操作:
int m = Arrays.stream(ints).parallel().reduce(Integer.MIN_VALUE, Math::max);我們的期望是并行執行應該比順序執行更快。 由于測量是在雙核平臺上進行的,因此并行執行最多可以是順序執行的兩倍。 理想情況下,順序/并行性能之比應為2.0。自然地,并行執行確實會引入一些開銷,用于拆分問題,創建子任務,在多個線程中運行子任務,收集其部分結果以及產生總體結果。 該比率將小于2.0,但應該接近。
這些是實際的基準測試結果:
sequential parallel seq./par. int-array 5.35 ms 3.35 ms 1.60通過我們的基準進行的現實檢查得出的比率(順序/并行)僅為1.6而不是2.0,這說明了并行執行涉及的開銷量以及(在此特定平臺上)如何(好壞)得到超額補償。
您可能會傾向于概括這些數字并得出結論,并行流始終比順序流快,也許不如人們希望的那樣快(在雙核硬件上),但是至少更快。 但是,事實并非如此。 同樣,有許多方面有助于并行流操作的性能。
其中之一是流源的可拆分性。 數組可以很好地拆分; 它只需要一個索引計算就可以找出中間元素并將數組分成兩半。 沒有開銷,因此幾乎沒有拆分成本。 與數組相比,集合拆分的難易程度如何? 拆分二叉樹或鏈表需要什么? 在某些情況下,對于不同類型的集合,您將觀察到截然不同的性能結果。
另一個方面是有狀態性。 一些流操作保持狀態。 一個示例是distinct()操作。 這是一個中間操作,可消除輸入序列中的重復項,即,它返回具有不同元素的輸出序列。 為了確定下一個元素是否重復,該操作必須與它已經遇到的所有元素進行比較。 為此,它維護某種數據結構作為其狀態。 如果在并行流上調用distinct() ,則其狀態將被多個工作線程并發訪問,這需要某種形式的協調或同步,這會增加開銷,從而減慢并行執行的速度,最大程度地降低了并行執行的程度。比順序執行慢。
考慮到這一點,可以公平地說,流的性能模型并非微不足道。 幼稚地期望并行流操作總是比順序流操作快。 性能提升(如果有的話)取決于許多因素,我在上面簡要提到了其中的一些因素。 如果您熟悉流的內部工作原理,則可以對并行流操作的性能做出明智的猜測。 但是,您需要進行大量基準測試,以便針對給定的上下文確定并行進行是否值得。 實際上,在某些情況下,并行執行要比順序執行慢,并且在所有情況下盲目使用并行流可能會適得其反。
實現是:是的,并行流操作易于使用,并且通常比順序操作運行得更快,但是不要指望奇跡。 另外,不要猜測; 相反,要進行很多基準測試。
這是《 JAX雜志》的先睹為快–在此處注冊以獲取更多免費的開發人員提示,趨勢和教程。
翻譯自: https://www.javacodegeeks.com/2015/07/java-performance-tutorial-how-fast-are-the-java-8-streams.html
java8流分組 性能
總結
以上是生活随笔為你收集整理的java8流分组 性能_Java性能教程– Java 8流有多快?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么在电脑上安装应用(怎么在电脑上安装应
- 下一篇: hibernate性能_改善Hibern