牛逼哄洪的 Java 8 Stream和屎,性能也牛逼么?

Java8的Stream API可以極大提高Java程序員的生產(chǎn)力春瞬,讓程序員寫出高效率眶俩、干凈、簡(jiǎn)潔的代碼快鱼。

那么颠印,Stream API的性能到底如何呢,代碼整潔的背后是否意味著性能的損耗呢抹竹?本文對(duì)Stream API的性能一探究竟线罕。

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

測(cè)試所用代碼在這里

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

測(cè)試結(jié)果匯總

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

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

性能測(cè)試并不是容易的事袄琳,Java性能測(cè)試更費(fèi)勁询件,因?yàn)樘摂M機(jī)對(duì)性能的影響很大燃乍,JVM對(duì)性能的影響有兩方面:

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ù)會(huì)將熱點(diǎn)代碼在JVM運(yùn)行的過(guò)程中編譯成本地代碼英古,測(cè)試時(shí)我們會(huì)先對(duì)程序預(yù)熱,觸發(fā)對(duì)測(cè)試函數(shù)的即時(shí)編譯昙读。相關(guān)的JVM參數(shù)是 -XX:CompileThreshold=10000召调。

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

測(cè)試數(shù)據(jù)由程序隨機(jī)生成某残。為防止一次測(cè)試帶來(lái)的抖動(dòng),測(cè)試4次求出平均時(shí)間作為運(yùn)行時(shí)間陵吸。

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

測(cè)試內(nèi)容:找出整型數(shù)組中的最小值。對(duì)比f(wàn)or循環(huán)外部迭代和Stream API內(nèi)部迭代性能介牙。

測(cè)試程序 IntTest

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

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

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

1、對(duì)于基本類型Stream串行迭代的性能開銷明顯高于外部迭代開銷(兩倍)环础;

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

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

分析贯钩,對(duì)于基本類型:

1募狂、使用Stream并行API在單核情況下性能很差,比Stream串行API的性能還差角雷;

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

以上兩個(gè)測(cè)試說(shuō)明,對(duì)于基本類型的簡(jiǎn)單迭代吗坚,Stream串行迭代性能更差祈远,但多核情況下Stream迭代時(shí)性能較好呆万。

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

再來(lái)看對(duì)象的迭代效果。

測(cè)試內(nèi)容:找出字符串列表中最小的元素(自然順序)车份,對(duì)比f(wàn)or循環(huán)外部迭代和Stream API內(nèi)部迭代性能谋减。

測(cè)試程序StringTest

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

對(duì) Stream 不熟悉的,可以關(guān)注微信公眾號(hào):Java技術(shù)棧躬充,在后臺(tái)回復(fù):Java逃顶。

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

結(jié)果分析如下:

1、對(duì)于對(duì)象類型Stream串行迭代的性能開銷仍然高于外部迭代開銷(1.5倍)充甚,但差距沒(méi)有基本類型那么大以政。

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

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

分析盈蛮,對(duì)于對(duì)象類型:

1、使用Stream并行API在單核情況下性能比f(wàn)or循環(huán)外部迭代差技矮;

2抖誉、隨著使用核數(shù)的增加,Stream并行效果逐漸變好衰倦,多核帶來(lái)的效果明顯袒炉。

以上兩個(gè)測(cè)試說(shuō)明,對(duì)于對(duì)象類型的簡(jiǎn)單迭代樊零,Stream串行迭代性能更差我磁,但多核情況下Stream迭代時(shí)性能較好。

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

從實(shí)驗(yàn)一驻襟、二的結(jié)果來(lái)看夺艰,Stream串行執(zhí)行的效果都比外部迭代差(很多),是不是說(shuō)明Stream真的不行了沉衣?先別下結(jié)論郁副,我們?cè)賮?lái)考察一下更復(fù)雜的操作。

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

我們將訂單簡(jiǎn)化為 <userName,price,timeStamp>構(gòu)成的元組肥隆,并用 Order對(duì)象來(lái)表示愕贡。測(cè)試程序ReductionTest

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

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

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

1巷屿、Stream API的性能普遍好于外部手動(dòng)迭代固以,并行Stream效果更佳;

再來(lái)考察并行度對(duì)并行效果的影響,測(cè)試結(jié)果如下:

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

1诫钓、使用Stream并行歸約在單核情況下性能比串行歸約以及手動(dòng)歸約都要差,簡(jiǎn)單說(shuō)就是最差的篙螟;

2菌湃、隨著使用核數(shù)的增加,Stream并行效果逐漸變好遍略,多核帶來(lái)的效果明顯惧所。

以上兩個(gè)實(shí)驗(yàn)說(shuō)明,對(duì)于復(fù)雜的歸約操作绪杏,Stream串行歸約效果好于手動(dòng)歸約下愈,在多核情況下,并行歸約效果更佳蕾久。我們有理由相信势似,對(duì)于其他復(fù)雜的操作,Stream API也能表現(xiàn)出相似的性能表現(xiàn)僧著。

結(jié)論

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

1履因、對(duì)于簡(jiǎn)單操作,比如最簡(jiǎn)單的遍歷盹愚,Stream串行API性能明顯差于顯示迭代栅迄,但并行的Stream API能夠發(fā)揮多核特性。

2皆怕、對(duì)于復(fù)雜操作毅舆,Stream串行API性能可以和手動(dòng)實(shí)現(xiàn)的效果匹敵,在并行執(zhí)行時(shí)Stream API效果遠(yuǎn)超手動(dòng)實(shí)現(xiàn)端逼。

所以,如果出于性能考慮

1污淋、對(duì)于簡(jiǎn)單操作推薦使用外部迭代手動(dòng)實(shí)現(xiàn)

2顶滩、對(duì)于復(fù)雜操作,推薦使用Stream API

3寸爆、在多核情況下礁鲁,推薦使用并行Stream API來(lái)發(fā)揮多核優(yōu)勢(shì),

4赁豆、單核情況下不建議使用并行Stream API仅醇。

如果出于代碼簡(jiǎn)潔性考慮,使用Stream API能夠?qū)懗龈痰拇a魔种。即使是從性能方面說(shuō)析二,盡可能的使用Stream API也另外一個(gè)優(yōu)勢(shì),那就是只要Java Stream類庫(kù)做了升級(jí)優(yōu)化,代碼不用做任何修改就能享受到升級(jí)帶來(lái)的好處叶摄。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末属韧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蛤吓,更是在濱河造成了極大的恐慌宵喂,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件会傲,死亡現(xiàn)場(chǎng)離奇詭異锅棕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)淌山,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門裸燎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人艾岂,你說(shuō)我怎么就攤上這事顺少。” “怎么了王浴?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵脆炎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我氓辣,道長(zhǎng)秒裕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任钞啸,我火速辦了婚禮几蜻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘体斩。我一直安慰自己梭稚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布絮吵。 她就那樣靜靜地躺著弧烤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蹬敲。 梳的紋絲不亂的頭發(fā)上暇昂,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音伴嗡,去河邊找鬼急波。 笑死,一個(gè)胖子當(dāng)著我的面吹牛瘪校,可吹牛的內(nèi)容都是我干的澄暮。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼赏寇!你這毒婦竟也來(lái)了吉嫩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嗅定,失蹤者是張志新(化名)和其女友劉穎自娩,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渠退,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡忙迁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了碎乃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姊扔。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖梅誓,靈堂內(nèi)的尸體忽然破棺而出恰梢,到底是詐尸還是另有隱情,我是刑警寧澤梗掰,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布嵌言,位于F島的核電站,受9級(jí)特大地震影響及穗,放射性物質(zhì)發(fā)生泄漏摧茴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一埂陆、第九天 我趴在偏房一處隱蔽的房頂上張望苛白。 院中可真熱鬧,春花似錦焚虱、人聲如沸购裙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)躏率。三九已至,卻和暖如春谍咆,著一層夾襖步出監(jiān)牢的瞬間禾锤,已是汗流浹背私股。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工摹察, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人倡鲸。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓供嚎,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子克滴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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