在2024年初,一個(gè)名為Gunnar Morling的開(kāi)發(fā)者發(fā)布了一項(xiàng)名為“十億行挑戰(zhàn)”(The One Billion Row Challenge,簡(jiǎn)稱(chēng)1BRC)的編程競(jìng)賽,迅速引起了技術(shù)社區(qū)的廣泛關(guān)注。這項(xiàng)挑戰(zhàn)要求參賽者解析一個(gè)包含十億行氣象站溫度數(shù)據(jù)的大文件,并計(jì)算每個(gè)氣象站的最小、最大和平均溫度,最后按字典序輸出結(jié)果。
挑戰(zhàn)的核心文件是一個(gè)巨大的文本文件,每行記錄一個(gè)氣象站及其對(duì)應(yīng)的溫度值,格式簡(jiǎn)單明了:氣象站名稱(chēng)與溫度值之間用分號(hào)分隔,溫度值保留一位小數(shù)。盡管需求看似簡(jiǎn)單,但文件的大小卻達(dá)到了驚人的13GB,對(duì)于普通計(jì)算機(jī)來(lái)說(shuō),處理如此龐大的數(shù)據(jù)集無(wú)疑是一項(xiàng)艱巨的任務(wù)。
官方提供了一個(gè)基線版本的Java代碼,使用流式編程和`groupingBy`方法進(jìn)行數(shù)據(jù)處理,避免了浮點(diǎn)計(jì)算以提高效率。然而,即使在高性能的服務(wù)器上,該基線版本也需要大約2分鐘才能完成處理。相比之下,普通計(jì)算機(jī)上的運(yùn)行時(shí)間更是接近14分鐘。
然而,真正的挑戰(zhàn)才剛剛開(kāi)始。當(dāng)比賽結(jié)果公布時(shí),人們驚訝地發(fā)現(xiàn),一些參賽者竟然能在短短幾秒內(nèi)完成這項(xiàng)任務(wù)。其中,第一名選手在1.5秒內(nèi)就完成了整個(gè)處理過(guò)程,這一成績(jī)讓許多人難以置信。畢竟,光是讀取13GB的文件也需要一定時(shí)間,更不用說(shuō)解析和計(jì)算了。
為了揭開(kāi)這些高手的秘密,我們深入研究了他們的代碼。盡管這些代碼對(duì)于普通開(kāi)發(fā)者來(lái)說(shuō)可能難以理解,但它們的優(yōu)化思路卻值得我們學(xué)習(xí)。例如,第一名選手的代碼采用了多種高級(jí)優(yōu)化技術(shù),包括并行I/O、內(nèi)存映射、位運(yùn)算等,極大地提高了數(shù)據(jù)處理速度。
其中一位名為Marko Topolnik的參賽者,在比賽結(jié)束后繼續(xù)優(yōu)化他的代碼,最終將運(yùn)行時(shí)間縮短到了1.7秒。他詳細(xì)記錄了自己的優(yōu)化過(guò)程,從最初的71秒到最終的1.7秒,每一步都充滿了智慧和汗水。他的優(yōu)化策略包括更換JVM、并行I/O、優(yōu)化溫度解析方法、自定義哈希表以及使用`Unsafe`和SWAR技術(shù)等。
Marko Topolnik的優(yōu)化過(guò)程充分展示了數(shù)據(jù)指標(biāo)的重要性。他通過(guò)收集和分析程序的運(yùn)行指標(biāo),找到了性能瓶頸,并針對(duì)性地進(jìn)行了優(yōu)化。例如,他通過(guò)火焰圖發(fā)現(xiàn)`BufferedReader`占用了大量性能,于是采用了并行I/O和內(nèi)存映射技術(shù)來(lái)提高讀取速度。同時(shí),他還通過(guò)自定義哈希表和位運(yùn)算技術(shù)來(lái)減少內(nèi)存消耗和提高計(jì)算速度。
這些高手的代碼雖然難以理解,但他們的優(yōu)化思路卻對(duì)我們有很大的啟發(fā)。他們教會(huì)我們?nèi)绾卧诿鎸?duì)龐大數(shù)據(jù)集時(shí),通過(guò)巧妙的算法和高效的編程技巧來(lái)提高數(shù)據(jù)處理速度。這些經(jīng)驗(yàn)不僅對(duì)于參加編程競(jìng)賽有用,更對(duì)于我們?nèi)粘5墓ぷ骱蛯W(xué)習(xí)具有重要的指導(dǎo)意義。
通過(guò)這次挑戰(zhàn),我們不僅見(jiàn)識(shí)到了高手們的編程實(shí)力,更深刻體會(huì)到了技術(shù)優(yōu)化的魅力和重要性。在未來(lái)的工作中,我們或許不會(huì)經(jīng)常遇到如此龐大的數(shù)據(jù)集,但掌握這些優(yōu)化技巧無(wú)疑會(huì)讓我們?cè)谔幚砀鞣N復(fù)雜問(wèn)題時(shí)更加得心應(yīng)手。