牛逼哄洪的 Java 8 Stream,性能也牛逼么激况?

Java8的Stream API可以極大提高Java程序員的生產(chǎn)力作彤,讓程序員寫出高效率膘魄、干凈乌逐、簡潔的代碼。

那么创葡,Stream API的性能到底如何呢浙踢,代碼整潔的背后是否意味著性能的損耗呢?本文對Stream API的性能一探究竟灿渴。

為保證測試結(jié)果真實(shí)可信洛波,我們將JVM運(yùn)行在 -server模式下,測試數(shù)據(jù)在GB量級骚露,測試機(jī)器采用常見的商用服務(wù)器蹬挤,配置如下:

? OSCentOS 6.7 x86_64

CPUIntel Xeon X5675, 12M Cache 3.06 GHz, 6 Cores 12 Threads

內(nèi)存96GB

JDKjava version 1.8.0_91, Java HotSpot(TM) 64-Bit Server VM

測試所用代碼在這里

https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/perf/StreamBenchmark/src/lee

測試結(jié)果匯總

https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/perf/Stream_performance.xlsx

測試方法和測試數(shù)據(jù)

性能測試并不是容易的事,Java性能測試更費(fèi)勁棘幸,因?yàn)樘摂M機(jī)對性能的影響很大焰扳,JVM對性能的影響有兩方面:

1、GC的影響误续。GC的行為是Java中很不好控制的一塊吨悍,為增加確定性,我們手動(dòng)指定使用CMS收集器蹋嵌,并使用10GB固定大小的堆內(nèi)存育瓜。集體到JVM參數(shù)就是 -XX:+UseConcMarkSweepGC-Xms10G-Xmx10G

2、JIT(Just-In-Time)即時(shí)編譯技術(shù)栽烂。即時(shí)編譯技術(shù)會將熱點(diǎn)代碼在JVM運(yùn)行的過程中編譯成本地代碼躏仇,測試時(shí)我們會先對程序預(yù)熱恋脚,觸發(fā)對測試函數(shù)的即時(shí)編譯。相關(guān)的JVM參數(shù)是 -XX:CompileThreshold=10000焰手。

Stream并行執(zhí)行時(shí)用到 ForkJoinPool.commonPool()得到的線程池慧起,為控制并行度我們使用Linux的 taskset命令指定JVM可用的核數(shù)。


測試數(shù)據(jù)由程序隨機(jī)生成册倒。為防止一次測試帶來的抖動(dòng)蚓挤,測試4次求出平均時(shí)間作為運(yùn)行時(shí)間。

實(shí)驗(yàn)一 基本類型迭代

測試內(nèi)容:找出整型數(shù)組中的最小值驻子。對比for循環(huán)外部迭代和Stream API內(nèi)部迭代性能灿意。

測試程序 IntTest

https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/perf/StreamBenchmark/src/lee/IntTest.java

測試結(jié)果如下圖:


圖中展示的是for循環(huán)外部迭代耗時(shí)為基準(zhǔn)的時(shí)間比值。分析如下:

1崇呵、對于基本類型Stream串行迭代的性能開銷明顯高于外部迭代開銷(兩倍)缤剧;

2、Stream并行迭代的性能比串行迭代和外部迭代都好域慷。

并行迭代性能跟可利用的核數(shù)有關(guān)荒辕,上圖中的并行迭代使用了全部12個(gè)核,為考察使用核數(shù)對性能的影響犹褒,我們專門測試了不同核數(shù)下的Stream并行迭代效果:


分析抵窒,對于基本類型:

1、使用Stream并行API在單核情況下性能很差叠骑,比Stream串行API的性能還差李皇;

2、隨著使用核數(shù)的增加宙枷,Stream并行效果逐漸變好掉房,比使用for循環(huán)外部迭代的性能還好。

以上兩個(gè)測試說明慰丛,對于基本類型的簡單迭代卓囚,Stream串行迭代性能更差,但多核情況下Stream迭代時(shí)性能較好诅病。

實(shí)驗(yàn)二 對象迭代

再來看對象的迭代效果哪亿。

測試內(nèi)容:找出字符串列表中最小的元素(自然順序),對比for循環(huán)外部迭代和Stream API內(nèi)部迭代性能睬隶。

測試程序StringTest

https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/perf/StreamBenchmark/src/lee/StringTest.java

對 Stream 不熟悉的锣夹,可以關(guān)注微信公眾號:Java技術(shù)棧,在后臺回復(fù):Java苏潜。

測試結(jié)果如下圖:


結(jié)果分析如下:

1银萍、對于對象類型Stream串行迭代的性能開銷仍然高于外部迭代開銷(1.5倍),但差距沒有基本類型那么大恤左。

2、Stream并行迭代的性能比串行迭代和外部迭代都好。

再來單獨(dú)考察Stream并行迭代效果:


分析征唬,對于對象類型:

1义郑、使用Stream并行API在單核情況下性能比for循環(huán)外部迭代差近范;

2、隨著使用核數(shù)的增加,Stream并行效果逐漸變好,多核帶來的效果明顯麻捻。

以上兩個(gè)測試說明,對于對象類型的簡單迭代呀袱,Stream串行迭代性能更差贸毕,但多核情況下Stream迭代時(shí)性能較好。

實(shí)驗(yàn)三 復(fù)雜對象歸約

從實(shí)驗(yàn)一夜赵、二的結(jié)果來看明棍,Stream串行執(zhí)行的效果都比外部迭代差(很多),是不是說明Stream真的不行了寇僧?先別下結(jié)論摊腋,我們再來考察一下更復(fù)雜的操作。

測試內(nèi)容:給定訂單列表嘁傀,統(tǒng)計(jì)每個(gè)用戶的總交易額兴蒸。對比使用外部迭代手動(dòng)實(shí)現(xiàn)和Stream API之間的性能。

我們將訂單簡化為 <userName,price,timeStamp>構(gòu)成的元組心包,并用 Order對象來表示类咧。測試程序ReductionTest

https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/perf/StreamBenchmark/src/lee/ReductionTest.java

測試結(jié)果如下圖:

分析馒铃,對于復(fù)雜的歸約操作:

1蟹腾、Stream API的性能普遍好于外部手動(dòng)迭代,并行Stream效果更佳区宇;

再來考察并行度對并行效果的影響娃殖,測試結(jié)果如下:

分析,對于復(fù)雜的歸約操作:

1议谷、使用Stream并行歸約在單核情況下性能比串行歸約以及手動(dòng)歸約都要差炉爆,簡單說就是最差的;

2卧晓、隨著使用核數(shù)的增加芬首,Stream并行效果逐漸變好,多核帶來的效果明顯逼裆。

以上兩個(gè)實(shí)驗(yàn)說明郁稍,對于復(fù)雜的歸約操作,Stream串行歸約效果好于手動(dòng)歸約胜宇,在多核情況下耀怜,并行歸約效果更佳恢着。我們有理由相信,對于其他復(fù)雜的操作财破,Stream API也能表現(xiàn)出相似的性能表現(xiàn)掰派。

結(jié)論

上述三個(gè)實(shí)驗(yàn)的結(jié)果可以總結(jié)如下:

1、對于簡單操作左痢,比如最簡單的遍歷靡羡,Stream串行API性能明顯差于顯示迭代,但并行的Stream API能夠發(fā)揮多核特性俊性。

2亿眠、對于復(fù)雜操作,Stream串行API性能可以和手動(dòng)實(shí)現(xiàn)的效果匹敵磅废,在并行執(zhí)行時(shí)Stream API效果遠(yuǎn)超手動(dòng)實(shí)現(xiàn)纳像。

所以,如果出于性能考慮

1拯勉、對于簡單操作推薦使用外部迭代手動(dòng)實(shí)現(xiàn)?

2竟趾、對于復(fù)雜操作,推薦使用Stream API?

3宫峦、在多核情況下岔帽,推薦使用并行Stream API來發(fā)揮多核優(yōu)勢,?

4导绷、單核情況下不建議使用并行Stream API犀勒。

如果出于代碼簡潔性考慮,使用Stream API能夠?qū)懗龈痰拇a妥曲。即使是從性能方面說贾费,盡可能的使用Stream API也另外一個(gè)優(yōu)勢,那就是只要Java Stream類庫做了升級優(yōu)化檐盟,代碼不用做任何修改就能享受到升級帶來的好處褂萧。

作者:CarpenterLee

來源:https://dwz.cn/pSW0u0Qr

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市葵萎,隨后出現(xiàn)的幾起案子导犹,更是在濱河造成了極大的恐慌,老刑警劉巖羡忘,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谎痢,死亡現(xiàn)場離奇詭異,居然都是意外死亡卷雕,警方通過查閱死者的電腦和手機(jī)节猿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爽蝴,“玉大人沐批,你說我怎么就攤上這事纫骑。” “怎么了九孩?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵先馆,是天一觀的道長。 經(jīng)常有香客問我躺彬,道長煤墙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任宪拥,我火速辦了婚禮仿野,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘她君。我一直安慰自己脚作,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布缔刹。 她就那樣靜靜地躺著球涛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪校镐。 梳的紋絲不亂的頭發(fā)上亿扁,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機(jī)與錄音鸟廓,去河邊找鬼从祝。 笑死,一個(gè)胖子當(dāng)著我的面吹牛引谜,可吹牛的內(nèi)容都是我干的牍陌。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼煌张,長吁一口氣:“原來是場噩夢啊……” “哼呐赡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起骏融,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎萌狂,沒想到半個(gè)月后档玻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡茫藏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年误趴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片务傲。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凉当,死狀恐怖枣申,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情看杭,我是刑警寧澤忠藤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站楼雹,受9級特大地震影響模孩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜贮缅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一榨咐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谴供,春花似錦块茁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至轴或,卻和暖如春昌跌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背照雁。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工蚕愤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人饺蚊。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓萍诱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親污呼。 傳聞我的和親對象是個(gè)殘疾皇子裕坊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容