多執行緒

  • 4168
  • 0

多執行緒

今天在研究委派及多執行緒的使用方式

找到了一篇不錯的介紹文章,借用了Marlon大大的文章來增加自己的專業知識

 

不同的應用程式,在作業系統中是以處理序 (Process) 做為分隔,讓不同的應用程式間不會相互干擾,我們從 Windows 工作管理員可以看到幾個頁籤,其中「應用程式」頁是指有視窗的應用程式,「處理程序」頁則列出所有正在執行的處理序。執行緒 (Thread) 是作業系統分配處理器 (CPU) 時間的基本單元,也就是當應用程式在執行時是經由執行緒向作業系統申請處理器的使用權。因為同一時間一個處理器只能給一個執行緒使用,作業系統中所有正在執行的處理序所建立的所有執行緒需要使用處理器時,會在一個佇列中等候作業系統分配可用的處理器時間,當執行緒使用處理器的時間量超過限額時就會暫止,由佇列中下一個執行緒繼續使用。每段時間量的長度視作業系統和處理器而定,由於這是一個極短的時間,例如每一個執行緒使用10毫秒,1秒鐘就會有100個執行緒次被執行,因此即使只有一個處理器,看起來就像多個執行緒同時在執行一樣,但終究和多工有所不同,多工是指不管把時間細分到多小都還是同時執行。執行緒的內容包含其主處理序的位址空間中能順利繼續執行所需的所有資訊,包括一組 CPU 暫存器和堆疊。每個執行緒會維護例外處理常式 (Exception Handler)、排程優先權,以及系統用來在執行緒排程之前儲存其內容的一組結構。

一個處理序可同時使用多個執行緖,那什麼時候應該使用多執行緒呢?使用多執行緒最大的好處在於讓工作同時開工,如果我們使用單一執行緒執行一段會耗時很久的程式碼,這段時間無法經由使用者介面得到回應,這對使用者而言是很不愉快的經驗,不知道到底是當機還是仍在作業中,也無法取消工作(除非直接結束應用程式)。如果使用多執行緒,就能讓一個執行緒儘量保持在閒置狀態以便快速回應使用者,另一方面又可以同時在其他執行緒進行作業,如果再搭配執行進度的回報,使用者就可以清楚地知道到底進行了多少工作,還有多少工作未完成。使用多執行緒另一個可能得到的好處是可以節省無謂的等待時間,例如開發一個分散式系統,我們可能會遇到這樣的狀況:

單一執行緒

步驟 動作 耗時 (秒)
1 讀取資料 A 5
2 傳送資料 A 給 WebService1 處理後回傳資料 A1 10
3 讀取資料 B 3
4 傳送資料 B 給 WebService2 處理後回傳資料 B1 15
5 合併資料A1, B1加工後得到最終結果 C 2
總耗時 35

假設同時讀取資料 A 與 B 所需要的時間仍然是 5 秒與 3 秒,同時請求 WebService1 與 WebService2 服務也是一樣,我們如果利用多執行緒把流程改成

多執行緒

步驟 動作 耗時 (秒)
1 建立執行緒 2 執行步驟 1.A
建立執行緒 3 執行步驟 1.B
等待執行緒 2 , 3 完成作業

執行緒 A

步驟 動作 耗時 (秒)
1.A.1 讀取資料 A 5
1.A.2 傳送資料 A 給 WebService1 處理後回傳資料 A1 10
總耗時 15

執行緒 B

步驟 動作 耗時 (秒)
1.B.1 讀取資料 B 3
1.B.2 傳送資料 B 給 WebService2 處理後回傳資料 B1 15
總耗時 18
18
2 合併資料A1, B1加工後得到最終結果 C 2
總耗時 20

結果總耗時從 35 秒減為 20 秒,因為使用單一執行緒時,即使後面的步驟與前面的步驟互不相關,還是得等前面的執行完才能接下去做,使用多執行緒分頭辦事比較有效率,在同一時間內可以同時執行多項工作,自然可以花較少的時間。但這不意味只要使用多執行緒就能節省空等的時間,執行緒只是幫忙跑腿把工作交給處理器,有沒有多個閒置的處理器可以同時作業?再來,這些工作是不是真的要耗用很多處理器時間?還是短暫經手後交給其他主機的處理器或 I/O 裝置等,如果是後面這種情形,本機處理器多寡就不重要了,真正的執行者有沒有空閒才是關鍵,如果不同的執行緒送交的工作最後還是找上同一個執行工作者,還是沒有辦法同時執行,就達不到縮短工時的效果了。所以使用多執行緒只能讓工作同時啟動,要工作能真的同時並行才能有效縮短工時,例如同時請求二個不同主機的網路服務。

聽說現今的作業系統或軟體根本無法發揮多核心處理器的效能,那使用多執行緒有沒有幫助呢?如果你希望雙核心的效能是單核的二倍,那可能要失望了,要讓多核心處理器同時執行一組指令集同心協力完成一件工作,效能才會隨核心數線性倍增,但目前能並行執行的處理器指令並不多,所以多核心處理器的效能確實沒有辦法被充分利用。那為什麼 CPU 還要往四核或更多核發展呢?關心 CPU 發展的人大概都知道,CPU速度要往上提升,耗電量增加的幅度會更大,其他週邊也追不上 CPU 的速度,相反地稍微讓 CPU 降頻,耗電量減少的幅度也相對較大,結果以相同的耗電量來看,使用二個較低頻核心的 CPU 得到的總頻率會大於單一較高頻核心的 CPU,這也算是一種效能的提升。問題是多核心處理器無法同時執行指令,這種變相的效能提升使用者根本只是看得到吃不到?多核心處理器無法同時執行指令加速完成一件工作,但可以同時執行不同的指令加速完成多件工作 ( 相較於使用同耗電量的單核心處理器獨立完成多項工作 ),現今電腦的應用愈來愈廣,資料量愈來愈大,工作愈來愈複雜,我們總是會找到更多的工作給電腦處理,所以多核心的 CPU 終究還是有英雄用武之地。瞭解到這一點,如果要讓你的多核心處理器大展身手,請記得要同時給它不同的工作做,大部份你可以讓它同時有不同工作可以做的方法就是同時執行數個應用程式,不是同時開啟就算,要真的有用到處理器運算 (我自己在家除了 DV 編輯外好像也沒有什麼程式需要大量處理器運算時間)。 同樣的道理,開發應用程式時如果可以把一個需要處理器長時間運算的工作拆成數個可以並行處理的小工作,就可以經由多執行緒同時交給多個處理器執行,就這點而言使用多執行緒比單一執行緒更能發揮多核心處理器的效能。但請記得使用多執行緒只能讓多項工作同時啟動,執行緒本身不是工作執行者,執行緒數量多寡不是影響工作執行進度的關鍵,且使用多執行緒是要付出相當的成本,就作業系統而言,管理執行緒需要額外的處理器時間與記憶體,一個應用程式使用大量的執行緒會排擠到其他應用程式,太多執行緒造成大塞車的結果是包含作業系統及所有應用程式幾乎都會動彈不得,想要從工作管理員關掉麻煩製造者都很困難,因為連工作管理員都無法回應。對程式開發者而言,使用多執行緒不容易控制程式碼的執行流程,容易發生錯誤且偵錯不易,不小心還會造成執行緒相互封鎖而形成死結。

使用多執行緒有優點也有缺點,如何決定是否該使用多執行緒呢?我認為一開始應該優先考慮使用單一執行緒,確認程式可以按步就班正確執行,如果其中有某些工作耗時特別久,首先應該檢討演算法有無改進的空間,有時使用不同的演算法可以得到大幅的改善,從數十分鐘縮短成數十秒鐘。如果仍無法有效縮短工作時間,且這些工作與使用者介面使用相同的執行緒,那最好是另外建立一個背景執行緒來執行這些工作,讓使用者介面可以繼續回應,否則使用者等了很久看到程式仍無回應,恐怕沒耐心繼續等下去,直接就把應用程式結束掉了。最後,嘗試找出這些工作中可以並行處理的部份,再從背景執行緒建立多個執行緒讓這些小工作同時開工,如果程式執行時期的外在環境允許,這些小工作就有可能同時並行達到縮短工時的效果。

關於執行緒更詳盡的說明,大家可以參考 MSDN 「執行緒和執行緒處理」,下一次我將介紹如何使用 .Net 開發多執行緒程式。

 

 

引用了http://blog.ithome.com.tw/trackback.php?id=23101的文章內容