1. 程式人生 > >CLR via C# 筆記 ----執行緒基礎

CLR via C# 筆記 ----執行緒基礎

在Windows中,程序是對應用程式需要的資源(記憶體)的抽象,就好像程式正在獨佔著這些資源(虛擬記憶體)一樣

執行緒是對執行應用程式的cpu的抽象,就好像這個程式正在獨佔著這個cpu一樣(然而此執行緒 會被其他執行緒搶佔)

在Windows中,程序是十分昂貴的,建立一個程序要花幾秒鐘的時間,必須分配大量記憶體且初始化,EXE和DLL檔案

必須從磁碟上載入,等等。相反,在Windows中建立執行緒則相對廉價。所以程式設計師傾向於多執行緒而不是多程序。

雖然執行緒相對廉價,但是他相對於其他系統資源來說卻仍然十分昂貴,所以,還是應該省著用,用的恰當。

基於此,CLR提供了執行緒池的功能。一個程序有一個CLR(極大多數情況), 一個CLR有一個執行緒池,這個執行緒池被程序中所有的AppDomain(在一個程序裡隔離多個應用程式記憶體空間的機制)共享。一開始執行緒池中沒有任何執行緒,直到給他的工作項佇列指派 了一個工作項

:

//這是靜態類ThreadPool中的一個方法,用來給執行緒池新增一個工作項 WaitCallback 等價於Action<object>
public static bool QueueUserWorkItem(WaitCallback callBack, object state);

此時,執行緒池會拿取這個工作項並建立一個執行緒,工作完成後,會把執行緒歸還執行緒池,下次可以繼續使用。

 

執行緒(虛擬地獨佔cpu)和其他所有的虛擬機制一樣,必然有空間和時間上的額外消耗

空間上,執行緒建立時系統需要給他建立一個執行緒核心物件(一個數據結構),用來存放 一組對執行緒自我描述的一些屬性,以及程序上下文(當執行緒被切換時,會將cpu所有暫存器的內容存放此處)。需要給他建立一個TEB(執行緒環境塊,大約4Kb,這個結構儲存著異常處理鏈,每當程式進入一個try塊時會新增一個節點,退出時刪除節點,這個結構還包含了”執行緒本地資料“,以及圖形介面需要用到的一些資料結構)

需要給他建立使用者模式棧(存放臨時變數,引數返回值和跳轉地址,大約1M的空間),核心模式棧(大約12K,提供安全的和核心互動的保障,機制類似於提交給核心的資料,先複製到這裡,並且無法修改)

時間上,當執行緒建立時,會給程序中所有非託管DLL發出一個通知,例如C-Runtime就需要這個通知來為執行緒初始化一些東西。

(只有非託管的DLL才會收到通知,他會影響效能,但是這個通知可以選擇不傳送)

最後,執行緒的最大消耗來自於所謂的上下文切換

當作業系統決定要切換掉cpu當前的這個執行緒時,會先將此時cpu的暫存器資料儲存到執行緒的上下文結構中,然後將另一個執行緒的上下文資料恢復到cpu的暫存器,如果這個執行緒是另一個程序的,還需要切換cpu看見的虛擬地址空間

更進一步的,當執行緒切換時,意味著存放在快取記憶體中的資料失去了意義,吃掉了專門為了快取命中而進行優化的努力

筆記總結,多執行緒可以顯著增加程式的效能,但是執行緒是昂貴的資源,使用不當,也非常容易負優化。