開場(chǎng)白
在之前的文章 《2004:當(dāng)CPU溫和地走入那個(gè)良夜》 中我講到了2000年后摩爾定律的終結(jié),CPU時(shí)鐘頻率定格,多核成為CPU發(fā)展的新方向,并行計(jì)算成為趨勢(shì)。
在談到并行計(jì)算的時(shí)候我們不得不提的就是阿姆達(dá)爾定律。
阿姆達(dá)爾定律即 Amdahl's Law。是由美國計(jì)算機(jī)科學(xué)家 Gene Amdahl (1922/11/16 – 2015/11/10)在 1967 年提出,旨在用公式描述在并行計(jì)算中多核處理器理論上能夠提高多少倍速度。沒錯(cuò),學(xué)術(shù)界總是領(lǐng)先工業(yè)界幾十年。上世紀(jì)六十年代,多核并不是剛需,而Amdahl老爺子提出的這一定律卻為幾十年后的程序員們指引了方向。
公式定義
在程序未使用多核時(shí),有如下定義:
x表示的就是程序的執(zhí)行時(shí)間,其實(shí)和相同。a表示可以并行計(jì)算的代碼耗時(shí)占比。
如果這個(gè)程序在N核的CPU上執(zhí)行,則新的執(zhí)行時(shí)間為:
由于性能和耗時(shí)一般是成反比的,即耗時(shí)越低,表明性能越好。所以可以用如下公式表示性能:
表示性能提速(新性能是舊性能的多少倍)的效果:
一般將這個(gè)比值稱為加速比,加速就是speed up,簡(jiǎn)寫做S:故有如下公式:
n 為并行節(jié)點(diǎn)處理個(gè)數(shù),可以理解為 CPU 的核心數(shù)。
舉例探討
別小看這個(gè)數(shù)學(xué)公式,他幾乎可以讓你避免做很多性能優(yōu)化方面的無用功。
建設(shè)你的線上服務(wù)跑在一個(gè)32核的機(jī)器上,服務(wù)代碼中有30%的代碼可以進(jìn)行并行化,那么進(jìn)行并行化改造之后的性能是之前的多少倍呢?
約等于1.41倍,從耗時(shí)結(jié)果上來看,建設(shè)原先總耗時(shí)是140毫秒,那么進(jìn)行完并行化優(yōu)化之后耗時(shí)將變成100毫秒左右。
而如果你的服務(wù)中只有5%的代碼可以進(jìn)行并行化改造,那么優(yōu)化之后的性能收益是:
性能變化幾乎不大。即使你給原先100毫秒的服務(wù),降低了5毫秒,變成100毫秒,但工作和產(chǎn)出不成正比,因?yàn)椴⑿酗@然會(huì)增加額外的系統(tǒng)復(fù)雜度和維護(hù)成本。
講到這,你會(huì)感覺,這不就是二八原則嗎?沒錯(cuò),阿姆達(dá)爾定律所闡明的道理和二八原則如初一折,但是他用更加數(shù)學(xué)化的語言,用準(zhǔn)確的公式定義出來了。他便足以讓我們?cè)谡介_展工作之前,便得以評(píng)估自己是否在做無用功,從而讓我們把精力聚焦到更有價(jià)值的部分。而傳統(tǒng)的二八原則只是模糊的定義了大概這么一類現(xiàn)象,但是不管是二還是八都是模糊的數(shù)字。類似的表述還有“長尾效應(yīng)”。
使用延伸
前面說到阿姆達(dá)爾定律定義出來的加速比公式,其實(shí)也可以推廣到非并行計(jì)算領(lǐng)域。也就是說即使我并不是在做服務(wù)的并行化改造,我依然能從這個(gè)公式中受益。這是為什么呢?
先不考慮外部IO的耗時(shí),當(dāng)然IO一般是大頭,但不在本文討論范圍再舉個(gè)例子。當(dāng)談到服務(wù)本身的性能優(yōu)化的時(shí)候,我們一下子可能會(huì)想到很多套路。比如C++語法優(yōu)化,減少拷貝,減少頻繁創(chuàng)建大對(duì)象。又比如系統(tǒng)級(jí)優(yōu)化,減少系統(tǒng)調(diào)用等等。這些都是好的。
但是如果一個(gè)優(yōu)化點(diǎn),其占比不高,那么其優(yōu)化帶來的收益也是有限的。再來一個(gè)例子,比如:假設(shè)一個(gè)程序耗時(shí)100ms,其中多次運(yùn)行某個(gè)邏輯總花費(fèi)了80ms。現(xiàn)在你能做一些優(yōu)化對(duì)其性能提升30%,那么對(duì)于程序整體的性能提升是多少呢?同樣阿姆達(dá)爾定律可以告訴你:
總體性能提升了22%。
而如果這個(gè)邏輯總花費(fèi)是10ms,你加班加點(diǎn)從大小周到996,對(duì)這個(gè)邏輯的性能提升了1倍!那么對(duì)程序整體的性能提升是多少呢?
雖然也提升了5%的性能,但是投入的時(shí)間顯然更多。
所以這就引出了阿姆達(dá)爾定律中的一個(gè)經(jīng)典教義:
如果被優(yōu)化代碼在程序整體運(yùn)行時(shí)間中占比不大,那么即使對(duì)它的優(yōu)化非常成功也是不值得的!
您別說我還真有切身說法。我們都知道系統(tǒng)調(diào)用的性能是很差的,很久以前,我集中解決了一下系統(tǒng)調(diào)用的問題,將一些可以不經(jīng)過系統(tǒng)調(diào)用的邏輯進(jìn)行替換。比如把time()
函數(shù)換成gettimeofday()
,當(dāng)然嚴(yán)格意義上來說gettimeofday()
也算系統(tǒng)調(diào)用,畢竟它也是在man手冊(cè)第二頁中的。但是Linux引入的VDSO
機(jī)制,將其進(jìn)行了優(yōu)化。這里不展開討論了。
這輪優(yōu)化后,本來信心滿滿等著和領(lǐng)導(dǎo)匯報(bào)工作成果,卻發(fā)現(xiàn)耗時(shí)幾乎無變化。心想:經(jīng)驗(yàn)主義害死人啊。
其實(shí)并不是“經(jīng)驗(yàn)”不對(duì),也不是“理論”有誤,只是我當(dāng)時(shí)并不知道這凌駕于其他任何優(yōu)化法則的:阿姆達(dá)爾定律!
系統(tǒng)調(diào)用雖然有性能問題,但是在我整個(gè)服務(wù)中的影響占比是不高的,這里當(dāng)然也不能單純的從代碼量來看,也要看一次系統(tǒng)調(diào)用大概花費(fèi)的時(shí)間。不過我說這個(gè)例子,倒也不是說我們就要對(duì)這種明知有性能損害,但占比不高的問題聽之任之。不不不,我也是有代碼潔癖的,只是說我們通過理論分析可以將這種優(yōu)化的優(yōu)先級(jí)降低,或者裹挾一些其他方面的優(yōu)化來一起做一個(gè)版本。
所以我還是奉勸大家先做一下大概的評(píng)估,這樣不至于你的辛勤工作在別人眼里看起來沒有卵用。或者也可以在向領(lǐng)導(dǎo)講述某次“失敗”的優(yōu)化的時(shí)候找點(diǎn)理論支撐。