前言
阿姆達爾定律(Amdahl's Law)提供了一個最佳情況的估算,即通過優(yōu)化系統(tǒng)的特定部分可以提升多少系統(tǒng)性能,用于預測并行任務中系統(tǒng)性能提升的理論上限。該定律是由計算機科學家吉恩·阿姆達爾(Gene Amdahl, 1922-2015)于1967年提出的。
1. 阿姆達爾定律公式
以一個處理已知數(shù)量輸入數(shù)據(jù)的程序為例。這類程序通常包含一組難以并行化的順序語句,以及一部分可以并行化的語句。
假設為P(Parallel)可并行化代碼所占總代碼的比例,如果使用N(Number)計算單元而不是單個線程來解決問題,S(Speedup)為預期的加速比,阿姆達爾定律如下:
S = 1 / (1 – P + P/N)
2. 阿姆達爾定律的好處
阿姆達爾定律有助于快速評估可用于系統(tǒng)加速方案的利弊。通過在計算鏈的某個部分投入更多硬件,我們可以確定能夠實現(xiàn)的加速倍數(shù)。
相反,我們可以利用該定律快速估算程序中哪些部分可以進行優(yōu)化,從而獲得最佳效果。如果我們嘗試通過并行化來加速以順序操作為主的代碼部分,那么它帶來的投資回報將非常有限。
3. 阿姆達爾定律的局限性
在N個處理器上并行運行代碼片段很少能帶來線性N倍數(shù)的速度提升。隨著程序中并行執(zhí)行線程數(shù)量的增加,擴展問題也開始出現(xiàn)。最好的情況是,運行時環(huán)境允許您將編程模型的線程映射到實際的物理中央處理單元線程和核心,但并非所有編程語言都支持此功能。
如果系統(tǒng)中的線程數(shù)超過處理器的可用線程數(shù),則必須處理上下文切換。這意味著線程會被中斷,其相關的內(nèi)部狀態(tài)會被保存,并且其緩存行(線程使用的內(nèi)部 CPU 緩存)會被刷新,例如,寫回內(nèi)存。
然后對新線程執(zhí)行相反的操作??紤]到主內(nèi)存比 CPU 慢一個數(shù)量級,上下文切換會引入延遲。
此外,當多個 CPU 核心并行運行時,內(nèi)存帶寬也會成為一個影響因素。它們處理的數(shù)據(jù)必須從隨機存取存儲器加載,并且至少要將結果寫回。任何上下文切換都意味著需要消耗額外的內(nèi)存帶寬來交換線程數(shù)據(jù)。
這就是為什么并行化帶來的性能提升從未實現(xiàn)線性增長,即使在代碼的并行化部分也是如此。阿姆達爾定律提供了一個最佳情況的估計。
4. 使用阿姆達爾定律的示例
在圖像處理中,假設你的程序讀取一些數(shù)據(jù),然后對每個數(shù)據(jù)項執(zhí)行獨立計算。讀取數(shù)據(jù)需要一分鐘,在單個 CPU 線程上處理數(shù)據(jù)又需要三分鐘。每個元素(圖像幀)都是獨立的,可以單獨處理。需要多少硬件才能將執(zhí)行速度提高一倍?
P是并行化的比例,它代表四分鐘中的三分鐘,因此P=3/4,即0.75。需要將執(zhí)行速度提升一倍,因此加速比S=2。使用上述阿姆達爾定律公式并求解N,可以得到下面的公式和計算結果:
N = P / (P - 1 - 1/S) = 0.75 / (0.75 – 1 – 1/2) = 3
需要用三個處理器來解決這個問題,將數(shù)據(jù)處理時間從三分鐘縮短到一分鐘。然而,數(shù)據(jù)加載仍然需要一分鐘。硬件成本增加了兩倍,但速度卻只提高了一倍。
另外,占總時間四分之一的讀取數(shù)據(jù)部分不會消失,即使其余并行代碼的執(zhí)行速度無限快(即在零秒內(nèi))。
該定律將一個直觀正確的觀察形式化:如果你選取代碼中可以優(yōu)化的部分并無限加快其速度,最后順序部分的執(zhí)行時間將成為瓶頸。
這個網(wǎng)址(https://www.desmos.com/calculator/dra8fw2cea)展示了阿姆達爾定律公式的坐標圖。通過點擊下圖左邊箭頭所指的按鈕,就可以看到加速比S隨著N的變化情況,而且也可以手動滑動來分析某一個N情況下,S隨著P的影響情況。
5. 阿姆達爾定律如何影響系統(tǒng)架構
內(nèi)存帶寬瓶頸只是性能考慮因素之一,大容量存儲和網(wǎng)絡帶來的延遲是另一個主要因素。例如,即使擁有最好的索引,訪問數(shù)據(jù)庫表也需要進行大量I/O 操作,而且每個操作都有其存儲或網(wǎng)絡延遲。
為了克服這一限制,系統(tǒng)架構師可以通過在內(nèi)存和外部 I/O 設備之間添加更多硬件通道來增加系統(tǒng)的 I/O 容量,或者通過添加不同的物理主機來水平擴展系統(tǒng)。這種水平擴展只有在主機能夠獨立處理數(shù)據(jù)記錄或片段的情況下才有意義。可以通過“分片”來實現(xiàn)這一點,這是一種常用的機制,將數(shù)據(jù)拆分成可獨立處理的片段。
例如,RAID1 驅動器陣列將相同的數(shù)據(jù)存儲在多個驅動器(稱為鏡像)中,以實現(xiàn)更快的讀取速度。訪問數(shù)據(jù)時,系統(tǒng)可以將訪問請求分散到多個驅動器上,從而加快程序的數(shù)據(jù)訪問速度。
6. 如何利用阿姆達爾定律優(yōu)化系統(tǒng)
即使將無限的資源投入到處理鏈的某個環(huán)節(jié),也無助于加速其余部分。優(yōu)化復雜系統(tǒng)的第一步是仔細觀察它,并確保我們了解它在各個環(huán)節(jié)的時間分配。
以代碼優(yōu)化為例:
第一步是在代碼中添加指標,用于觀察各代碼環(huán)節(jié)的延遲情況。利用這些指標可能需要一些復雜的設置。最基本的方法是定期將指標數(shù)據(jù)轉儲到存儲中。在企業(yè)環(huán)境中,程序員通常可以訪問監(jiān)控和遙測系統(tǒng),以便了解自己代碼的行為。否則,開發(fā)人員將不知道如何進行優(yōu)化。更糟糕的是,他們會盲目地花費精力改進某些代碼段,而這些代碼段在實際應用中卻并非決定性的性能因素,這通常被稱為“過早優(yōu)化”。
一旦收集了這些指標,開發(fā)人員可以嘗試將他們的代碼路徑描繪成時間/性能格式的圖表。例如,假設一個請求來自網(wǎng)絡。處理此請求將創(chuàng)建多次數(shù)據(jù)庫訪問,然后進行一些計算循環(huán)。這些操作中的每一個都可以有自己的指標。識別最長的代碼路徑并將其分解為單獨的計算和延遲時間間隔,然后集中精力找到最佳的優(yōu)化候選對象。
7. 總結
阿姆達爾定律不只是只能用于計算機科學中,也可用于生活、理財、做事等方方面面。平時可以多觀察、記錄和分析試試。