CIO
|
PCDIY!
|
DigitalHome
|
旗標圖書
|
旗景數位影像
|
旗標知識講堂
|
讀者服務
首 頁
即時新聞
最新活動
企業採購
精選文章
線上教學
雜誌目錄
程式碼下載
雲端運算智庫
Visual Studio 2010
Windows 7 FAQ
最近新增的文章
Zoner Photo Studio 12試用報導
EMC VPLEX跨IDC儲存新架構
Clavister Security Gateway高效能網路安全閘道
Lenovo ThinkCentre A70z
更成熟穩健的 Web Forms 4.0
建立開發團隊專屬的最佳Scrum流程
打造全新軟體測試與驗證中心
Visual Studio Team Explorer Everywhere整合帶來的優勢
輕鬆建構軟體藍圖
軟體生命週期的版本與流程控管
大幅降低平行運算開發的門檻
邁向雲端之路
前端介面之使用者經驗設計趨勢 ─ Silverlight 4.0
新一代整合式開發平台導覽
把Dynamic Data整合到Web Forms
最多人點閱的文章
ASP.NET MVC 1.0初探
MSN機器人開發(上)
Lynnfield上市 新款i5/i7效能比較
初探Hadoop開放原始碼平台環境
MSN機器人開發(下)
抗摔防潑水商用NB解密
Acer DX900 WM雙模雙待機
虛擬化環境下 資料備份與管理
Windows Server 基礎架構與管理的改善
Anti-rootkit工具介紹
ASP.NET AJAX Templates初探
虛擬化環境下資料備份與管理Part 2
惡意程式的隱形斗蓬-rootkit
ASP.NET AJAX Templates整合應用
耐用度指標商務機種—HP Elitebook
精選文章
分享到Plurk
分享到FaceBook
多執行緒控制技巧
生產線模式的多執行緒應用
文/圖 吳剛志.責任編輯/洪羿漣
要運用到多核心CPU的運算能力,最普遍的方法就是把工作切成多個獨立的小工作,指派給不同的執行緒(或是交給執行緒集區處理)執行,來提升整體的效能。但是複雜的工作並無法切割成獨立的小工作,一定要照順序執行。本文會介紹另一種「管線(Pipeline)」的設計方式,就像工廠的生產線一樣,能把一連串相依的工作交給多個執行緒個別執行,一樣能提升效能。
要開發多執行緒程式最大的障礙,一種是開發跟除錯的困難,另一種是很多程式本質上就很難切成多執行緒來增加效能。這時必需用另外的設計模式來解決這個問題。這次的範例程式延續上一篇[執行緒集區] 的例子:批次處理大量照片。只不過我們把需求調整一下,這次的要求是把每張照片(*.JPG)轉成縮圖(*.PNG)後,最後還要把所有的照片檔再壓縮成一個ZIP壓縮檔。
這個範例會碰到的障礙是:處理縮圖及壓縮ZIP檔都是需要大量CPU運算能力的動作,不過ZIP的壓縮動作,一定得等前面的縮圖處理完成後才能開工,而且壓成ZIP的部份不能像縮圖一樣切成多個執行緒同時進行,這樣的程式要能在多核心CPU系統下發揮效能,是設計上的一大挑戰。在大部份的情況下,工作都是有先後順序的。之前介紹的執行序集區,對這類的問題就起不了作用,因此本文提出另一種切割方式,能在這種情況下運用多執行緒:生產線。
生產線的運作模式
生產線的運作模式,是源自當年福特汽車廠用來大量生產汽車的作法。在開始寫程式前,我們先來瞭解它的運作方式。生產汽車是件很複雜的工作,整個過程有很多步驟,在輸送帶上每個步驟都有負責的人員,依序完成他的步驟,那麼當零件走到輸送帶的末端,車子就完成了。我們先來看看這張說明生產線運作方式的概念圖(圖1)。
圖1:生產線的運作概念圖。
假設生產一量車子要100小時,整個生產線把它平分成100個步驟,則每個步驟只要花費1小時。每個步驟完成之後,輸送帶會把半成品帶到下一個步驟,直到完成為止。
如果生產線只生產一台車子,是沒有任何好處的。如果生產線持續運作,結果就不一樣了。來看看每個步驟跟時間的關係圖(圖2)。
圖2:生產線的步驟與時間的關係圖。
扣掉一開始,後面階段還沒動起來的部份,每一個週期過了,都會有一輛車子完成。用上面的例子來看,每一個小時就可以完成一輛車。
這種模式的好處是簡單,而且容易實作。因為它是用生產線的模式,按照順序進行,因此一個大的工作很容易切割,因為不再有每個小工作必需能獨立運作的限制。生產線的步驟切的越細,則階段的週期就越短,相對的效率就越高。前面的例子每個小時就能完成一輛車,如果我們重新設計生產線,規劃為500個階段,則每個階段只需要12分鐘就能完成,換句話說最後每12分鐘就能生產一輛車,效率提升了500倍!
下一步─開始寫CODE
生產線的方法,特點就是能夠視情況需要,拉長生產線的階段,就能提高生產速度。概念暫時先介紹到這裡。我們回過頭來看看,這樣的工作安排方式能夠怎麼替我們解決問題? 這次的範例,我們該怎樣把它套用在生產線的模式?如圖3。
圖3:處理圖檔及壓縮作業的工廠意示圖。
圖4:沒有使用生產線的步驟及時間關係圖。
圖5:使用生產線的步驟及時間關係圖。
接下來看看程式的兩個階段與時間的關係圖。圖4是未採用生產線模式,而圖5則是採用生產線的方式,每個階段都由一個專用的執行緒來負責。可以看到因為採用生產線,所以兩個步驟在時間上就有部份重疊了,整體工作完成的時間少了一半。
程式的部份,先看看「MakeThumbPipeWorkItem」這類別怎麼把工作切成兩個階段,如程式1。接下來來看看生產線如何依序執行這一連串的工作,如程式2。
程式的邏輯並不難。調整一下原圖3的內容,這次直接把程式用到的資料結構跟類別直接標上去,如圖6。
圖6:生產線的程式流程圖。
概念上每個階段是靠輸送帶,把半成品從上一階段送到下一階段。程式實作則是用佇列(Queue
)來扮演兩個階段之間的輸送帶。原料(原圖檔)會包裝成PipeWorkItem物件,送到_stage1_queue,而_stage1_thread執行緒會不斷的把_stage1_queue裡的PipeWorkItem取出,執行完它的階段作業Stage1()之後,把半成品放到送到Stage2的佇列「_stage2_queue」。同樣的_stage2_thread執行緒也會不斷的把_stage2_queue內的PipeWorkItem取出執行Stage2( )。所有的PipeWorkItem都執行完畢之後,程式就完成它的任務了。而階段之間就靠ManualResetEvent: _notify_stage2來同步。必要時階段2會閒置,直到階段1通知它有新的工作才會醒過來。
執行結果及效能
先來看看執行的效率。為了做對照組,我特別準備了沒有採用執行緒的版本,要來看看兩者之間效能的差異。執行的環境及結果如下:
●作業系統:Vista SP1 (x64) 英文版。
●硬體配備:4核心CPU (Intel Q9300) + 8GB RAM。
●沒有採用執行緒的版本:執行共花掉了252.6秒;CPU使用率為25%~28%。
●採用生產線模式的版本:執行共花掉了164.6秒;CPU使用率為40%~45%。
效率有明顯的改善,約提升為1.5倍。為什麼執行的效率沒有如預期的變成一倍?這顯示了這種模式的第一個缺點:因為整個生產的過程是連續的,任何一個步驟耽誤了時間,則後面的步驟就會全部往後延。舉例來說,第一階段生產過慢,則第二階段沒事做就會閒置,反過來第一階段生產過快,半成品都會卡在_stage2_queue裡面,第二階段會來不及消化這些工作量,最後的影響就是效能的降低。
效能的改善
要最佳化整體效能的話,就要想辦法讓整個生產線流暢一點,不要發生效能的瓶頸,否則整個生產線會卡在最慢的那個階段。我們在執行Stage2的部份加上記時的物件(Stopwatch),來觀察看看Stage2是否有效能的問題。
很明顯的,看來壓縮ZIP的速度比處理縮圖還快,所以Stage2每處理完一個縮圖,都得閒置約400 msec後才等的到下一個工作,因此要調整的是在第一階段。改善的方法,不外乎是把第一階段再切成更小的步驟,不過從程式碼看來,已經沒有什麼地方可以切了。另一種方法,則是加派人手,多一組人馬來加快第一階段的作業,用兩倍的人力來處理第一階段,而第二階段效能比較好,繼續維持一組人馬負責就好。
再來看看調整過的程式碼如程式3,我們在第一階段加派人馬,多了一條專用的執行緒,因此原圖要調整成圖7。
圖7:第一階段加派人力。
修改過後,Stage2果然忙碌許多,除了偶爾的幾次閒置之外(閒置時間也不長,都在100 msec之內),其它都是忙碌的不停工作。當然修正的過程中,一樣要注意是否有ThreadSafe的問題,除了修改為一步驟多執行緒之外,也加上了lock鎖定,以確保程式碼是ThreadSafe的。修改過後的程式,執行共花掉了101.9秒,CPU使用率約為70%~74%。
讀者也許會發現,是不是能用上一篇文章提到的執行緒集區(ThreadPool)來加速第一階段的效能?當然可以,只不過千萬別加速過頭了。一方面用更多執行緒是能加速第一階段的產量沒錯,但是一來加速過頭讓第二階段跟不上,就沒用了。更糟的情況是第一階段佔用太多CPU運算資源,如果CPU核心數量不夠,也有可能讓第二階段的處理速度分掉,讓生產線各階段產能不平衡的問題更嚴重。
影響效能的因素
前面以汽車工廠生產線為例在討論效能問題時,曾提到步驟切的越多越有效,這個規則套用到我們的例子不一定適用。實際上要考慮的點有兩個地方。
步驟越多,則啟動及結束生產線的成本越高。
生產線剛啟動時,後面的階段其實都是閒置的。同樣的道理,生產線要停工時,前面的階段也會處於閒置狀態。因此設計時,生產線要怎麼切,是個影響效能的關鍵。切的階段越多,你需要更大量的訂單,才能攤平更高的生產線啟動及運作成本。半導體廠是另一個典型的例子,整個從晶圓到晶片的製作過程很長。因此你會常聽到新聞報導地震或是停電等因素造成生產線的停頓,損失金額高達數千萬元,就是這個道理。
切割的步驟數量過多,則效能提升有限。
我們的實作方式,是以特定的執行序來執行特定的步驟。同時間有過多的執行緒在執行,而CPU的核心速度或運算資源不足時,會讓每個階段的效能往下掉。CPU早就滿載了,當整體效能不能再往上提升時,啟動的成本又增加,對效能也有負面的影響。
平衡每個階段的產能
從上面的實際案例來看,要維持整體的效能,讓生產線順暢,會比最佳化某個階段的產能還要重要。因為整個生產線是連續的,最終的產能會受限於所有階段中最慢的一個。
結語
這篇文章主要的目的,是以另一種角度來利用多核心CPU的運算資源。常見的作法大都以水平的切割為主,把大量且獨立的運算丟給執行緒來處理。而本文以另一種角度,把工作做垂直的切割,分配給數個執行序來處理。希望這篇文章能帶給你另一種觀點,來解決你程式在多核CPU執行的效能問題。(完成程式碼請至www.runpc.com.tw下載)
【原文刊載於RUN!PC雜誌:2008年11月號】
回首頁...
關於RUN!PC
|
廣告刊登
|
聯絡我們
|
讀者服務
|
雜誌訂閱
|
出刊&補寄時間
|
招兵買馬
-- Copyright© FLAG INFORMATION CO., LTD. 旗訊科技(股)公司. All rights reserved. 本站圖文著作權所有 未經授權 不得任意轉載使用 --
-- 請使用1024*768螢幕解析度,IE 7.0或firefox 3.0以上瀏覽器,以達到最佳閱讀效果--