1. 程式人生 > >深入理解並行程式設計-分割和同步設計(三)

深入理解並行程式設計-分割和同步設計(三)

原文連結    作者:paul    譯者:謝寶友,魯陽,陳渝

設計準則

上面的章節中給出了三個並行程式設計的目標:效能、生產率和通用性。但是還需要更詳細的設計準則來真正的指導真實世界中的設計,這就是本節將解決的任務。在真實世界中,這些準則經常在某種程度上衝突,這需要設計者小心的權衡得失。

這些準則可以被認為是設計中的阻力,對這些阻力進行恰當權衡,這就稱為“設計模式”[Ale79],[GHJV95]。

基於三個並行程式設計目標的設計準則是加速、競爭、開銷、讀寫比率和複雜性。

加速:效能增加是花費如此多時間和精力進行並行化的主要原因。加速的定義是執行程式的順序執行版本所需要的時間,比上執行並行版本所需時間的比例。

競爭:如果對於一個並行程式來說,增加更多的CPU並不能讓程式忙起來,那麼多出來的CPU是因為競爭的關係而無法有效工作。可能是鎖競爭、記憶體競爭或者其他什麼效能殺手的原因。

工作-同步比率:單處理器、單執行緒、不可搶佔、不可中斷版本的並行程式完全不需要任何同步原語。因此,任何消耗在這些原語上(通訊中的cache miss、訊息延遲、加解鎖原語、原子指令和記憶體屏障等)的時間都是對程式意圖完成的工作沒有直接幫助的開銷。重要的衡量準則是同步開銷與臨界區中程式碼的開銷之間的關係,更大的臨界區能容忍更大的同步開銷。工作-同步開銷比率與同步效率的概念有關。

讀-寫比率:極少更新的資料結構更多是複製而不是分割,並且用非對稱的同步原語來保護,以提高寫者同步開銷的代價來降低讀者的同步開銷。對頻繁更新的資料結構的優化也是可以的,詳見第4章的討論。

複雜性:並行程式比相同的順序執行程式複雜,這是因為並行程式要比順序執行程式維護更多狀態,雖然這些狀態在某些情況下(有規律並且結構化的)理解起來很容易。並行程式員必須考慮同步原語、訊息傳遞、鎖的設計、臨界區識別以及死鎖等諸多問題。

更大的複雜性通常轉換成了更高的開發和維護代價。因此,程式碼預算可以有效限制對現有程式修改的數目和型別,因為原有程式在一定程度的加速只值這麼多的時間和精力。進一步說,還有可能對順序執行程式進行一定程度的優化,這比並行化更廉價、更有效。並行化只是眾多優化中的一種,並且只是一種主要應用於CPU是瓶頸的優化。

這些準則合在一起,讓程式達到了最大程度的加速。前三個準則相互交織在一起,所以本節剩下的部分將分析這三個準則的互動關係。

請注意,這些準則也是需求說明的一部份。必須,加速既是願望(“越快越好”),又是工作負荷的絕對需求,或者說是“執行環境”(“系統必須至少支援每秒1百萬次的web點選”)。

理解這些設計準則之間的關係,對於權衡並行程式的各個設計目標十分有用。

1. 程式在臨界區上所花的時間越少,潛在的加速就越大。這是Amdahl定律的結果,這也是因為在一個時刻只能只有一個CPU進入臨界區的原因。

2. 程式在某個互斥的臨界區上所耗費的時間必須大大小於CPU數的倒數,因為這樣增加CPU數目才能達到事實上的加速。比如在10個CPU上執行的程式只能在關鍵的臨界區上花費小於1/10的時間,這樣擴充套件性才好。

3. 競爭效應所浪費的多餘CPU和/或者本來該是加速的牆上時間,應該少於可用CPU的數目。CPU數和實際的加速之間的差距越大,CPU使用的效率越低。同樣,需要的效率越高,可以做到的加速就越小。

4. 如果可用的同步原語相較它們保護的臨界區來說開銷太大,那麼加速程式執行的最佳辦法是減少呼叫這些原語的次數(比如分批進入臨界區、資料所有權、RCU或者使用粒度更粗的設計——比如程式碼鎖)。

5. 如果臨界區相較守護這塊臨界區的原語來說開銷太大,那麼加速程式執行的最佳辦法是增加程式的並行化程度,比如使用讀寫鎖、資料鎖、RCU或者資料所有權。

6. 如果臨界區相較守護這塊臨界區的原語來說開銷太大,並且被守護的資料結構讀多於寫,那麼加速程式執行的最佳辦法是增加程式的並行化程度,比如讀寫鎖或者RCU。

7. 各種增加SMP效能的改動,比如減少鎖競爭程度,能改善響應時間。