Basic Of Concurrency(二十四: 阿姆達爾定律)

阿姆達爾定律能夠用來評估經過讓一個計算中的一部分並行處理的方式可以提高多少速度.阿姆達爾定律在1967年由Gene Amdal提出後得名.大部分從事併發編程的開放人員對併發帶來的增速都有很強的直覺.即便在他們不知道阿姆達爾定律的狀況下.可是仍然頗有必要知道阿姆達爾定律.html

咱們會先用算術的方式而後再用圖表的方式來說解阿姆達爾定律.java

阿姆達爾定律定義

一個程序或算法須要分紅兩部分來討論並行處理:算法

  • 不能被並行處理的部分
  • 可以被並行處理的部分

想象一個處理磁盤文件的程序.有一小部分程序用來掃描文件夾,並在內存中建立一個文件列表.而後纔是將每一個文件交給一個線程處理.掃描目錄和建立文件列表的部分不能被並行處理.而處理文件的這部分則能夠.編程

順序執行程序所須要的總時長咱們稱爲T.時間T包含了不能並行處理和可以並行處理兩部分的執行時間.不能並行處理的執行時長咱們稱爲B.可以並行處理的執行時長咱們稱爲T-B.如下列表中給出了具體的定義:小程序

  • T = 順序執行所須要的總時長
  • B = 不可以並行處理部分的執行時長
  • T - B = 可以並行處理部分的執行時長(只要是順序執行都不計入其中)

因此咱們有了以下定義:緩存

T = B + (T - B)
複製代碼

T - B所表示的可以並行處理的部分,能夠經過並行執行來提速.至於可以提高多少速度取決於使用了多少個線程來執行它.咱們用N來表示線程數量.最終咱們能夠用如下等式來表示並行部分所需的執行時長:網絡

(T - B) / N
複製代碼

另外一種寫法:併發

(1/N) * (T - B)
複製代碼

根據阿姆達爾定律,當經過N個線程來執行可並行處理部分後,程序的總執行時長能夠表示爲:post

T(N) = B + ( T(1) - B ) / N
複製代碼

這個等式仍然成立.優化

一個評估實例

爲了更好的理解阿姆達爾定律,咱們須要一個評估實例.咱們將程序的總執行時長設爲1.假設程序中不可並行處理部分佔比40%,執行時長佔比0.4,可並行處理部分佔比60%,執行時長佔比0.6.

假設程序的並行因子爲2(有兩個線程同時執行可並行處理部分, 因此N = 2)可得:

T(2) = 0.4 + ( 1 - 0.4 ) / 2
     = 0.4 + 0.6 / 2
     = 0.4 + 0.3
     = 0.7
複製代碼

若是將並行因子從2替換爲5可得:

T(5) = 0.4 + ( 1 - 0.4 ) / 5
     = 0.4 + 0.6 / 5
     = 0.4 + 0.12
     = 0.52
複製代碼

圖表講解阿姆達爾定律

爲了更好的理解阿姆達爾定律,咱們嘗試使用圖表來講明.

首先,一個程序能夠被分紅可並行處理部分B和不可並行處理部分1 - B,以下圖所示:

圖中上方給出的比例尺能夠用於表示程序順序執行所需的總時長T(1).

當咱們設置並行因子爲2時,執行時長以下圖所示:

當咱們設置並行因子爲3時,執行時長以下圖所示:

優化算法

根據阿姆達爾定律咱們能夠很天然的得出結論,程序中能夠被並行處理的部分能夠經過增長硬件來提速.(增長更多的線程和cpu數量).然而程序中不能並行處理的部分只能經過優化代碼來提速.所以,你能夠經過優化不可並行處理部分的代碼來提高運行速度和可並行性.你能夠經過更改算法的方式來減少程序不可並行處理部分的佔比,將一些計算移到並行處理部份內.

優化順序執行部分

當你優化程序同步執行的部分時,一樣可使用阿姆達爾定律來評估程序優化後帶來的運行增速.假設不可並行處理部分B的優化因子爲O,那麼阿姆達爾定律能夠表示爲:

T(O,N) = B / O + (1 - B / O) / N
複製代碼

記得,不可並行處理部分如今用B / O來表示,所以可並行處理部分須要用 1 - B / O來表示.

設B爲0.4, O爲2, N爲5, 可得出等式:

T(2,5) = 0.4 / 2 + (1 - 0.4 / 2) / 5
       = 0.2 + (1 - 0.4 / 2) / 5
       = 0.2 + (1 - 0.2) / 5
       = 0.2 + 0.8 / 5
       = 0.2 + 0.16
       = 0.36
複製代碼

執行時長 vs. 增速

咱們不僅僅可使用阿姆達爾定律來評估程序優化和並行處理後的執行時長.咱們還可使用阿姆達爾定律來評估增速,即得出新算法比舊的要快多少倍.

假設舊算法的執行時長爲T,則增速能夠表示爲:

Speedup = T / T(O,N)
複製代碼

咱們常常設置T爲1用分數的方式來表達新算法的執行時長比舊的要快多少倍.

等式能夠表示爲:

Speedup = 1 / T(O,N)
複製代碼

若是將T(O,N)替換爲阿姆達爾公式可得:

Speedup = 1 / ( B / O + (1 - B / O) / N )
複製代碼

設B=0.4, O=2, N=5, 由公式可得:

Speedup = 1 / ( 0.4 / 2 + (1 - 0.4 / 2) / 5)
        = 1 / ( 0.2 + (1 - 0.4 / 2) / 5)
        = 1 / ( 0.2 + (1 - 0.2) / 5 )
        = 1 / ( 0.2 + 0.8 / 5 )
        = 1 / ( 0.2 + 0.16 )
        = 1 / 0.36
        = 2.77777 ...
複製代碼

假設程序的不可並行處理部分的優化因子爲2,可並行處理部分的優化因子爲5,那麼新的算法實現大約比舊的版本要快2.77777倍.

要多測量而不僅是評估

雖然阿姆達爾定律能夠幫助你從理論上來評估一個算法並行化後的增速幅度.但不要太過依賴這些評估.實踐中,當你優化和並行化一個算法時還有許多其餘的因素參與進來共同影響程序的執行速度.

內存,cpu緩存,磁盤和網卡的讀寫速度等(若是有使用到磁盤和網絡的話)也會成爲限制因素.若是一個設計爲並行化的新算法執行過程當中,對CPU緩存的命中率太低的狀況下,也會達不到使用(T - B) x N的增速預期.一樣的,若是共享內存區域,磁盤或網卡和網絡連接時長處於過載的狀況下,也會達不到預期的增速效果.

更好的作法是使用阿姆達爾定律來評估程序中哪些地方須要優化,而經過測量的手段來檢查優化後帶來的增速.須要謹記的一點是一個高效的串行算法可能要比一個並行算法還要優越的多.不僅是由於串行執行中沒有額外的協做開銷(即須要分批處理任務再聚合處理所得結果),還由於單CPU算法能夠更加適應底層硬件的優化(CPU傳輸通道, CPU緩存等).

該系列博文爲筆者複習基礎所著譯文或理解後的產物,複習原文來自Jakob Jenkov所著Java Concurrency and Multithreading Tutorial

上一篇: 非阻塞算法下

相關文章
相關標籤/搜索