線程池
其實“線程池”就是用來存放“線程”的對象池。
線程池的作用
因為建立一個線程的代價較高,因此我們使用線程池設法複用線程。就這樣,在一個“池”中,儲存了一組可以反覆使用的線程對象,從而可以節省建立線程的開銷。
在.NET當中,雖然每次建立的SqlConnection對象是新的,但是這個對象內部所佔用的“資料庫連接”還是會複用。而用完 SqlConnection對象後的及時“關閉”(Dispose或Close),其實並沒有斷開資料庫連接,只是把這個串連放回了串連池。
CLR線程池
在.NET中,CLR線程 和 作業系統線程 對應。
您可以簡單地認為.NET中的Thread對象便封裝了一個作業系統線程,並附加了所需的資料。而CLR線程池便是存放這些CLR線程的對象池。
由於.NET內建的線程池在底層通過win32api調用的windows的進程附帶的線程池,所以對於進程,這個線程池是唯一的。很多.NET自身的操作也需要通過CLR線程池來完成,比如Timer。
注意:Thread對象只有當真正Start了之後,CLR才會建立一個作業系統線程與它綁定。
CLR線程池限制了線程的建立速度不超過每秒2個。
CLR線程池的作用:
1> 可以使用ThreadPool類的兩個靜態方法:QueueUserWorkItem 和 UnsafeUserQueueWorkItem 向CLR線程池中新增工作(一個WorkCallback委派物件)。
2> ASP.NET在得到一個請求後,也會將這個請求處理的任務交由CLR線程池在有空閑線程的時候得以執行。
3> ThreadPool.RegisterWaitForSingleObject 方法或是System.Threading.Timer 組件也會依賴CLR線程池。
如何設定ASP.NET的線程數
> 最大值
對於ASP.NET應用程式來說,CLR線程池容量代表了應用程式最多可以同時執行的請求數量。對於託管在IIS上的ASP.NET執行環境來說,這個值由全域配置決定。這個配置在machine.config檔案中system.web/processModel節點中,為maxWorkerThreads屬性,它決定了為單個處理器分配的線程數。如果這個值為40,且機器上擁有4個處理器(2 * 2CPU),那麼這台機器目前的配置表示在同一時刻,ASP.NET可以同時處理160個請求。某些參考資料建議您將其修改為每處理器80-100個線程,這時您只要修改相應的屬性值就可以了。
> 最小值
而在ASP.NET應用程式中,其machine.config設定檔的system.web/processModel節點的 minWorkerThreads屬性值,它代表了CLR線程池“總是會保留”的最少線程數量。在普通應用程式中這個值為“處理器數 * 1”。
注意:對於processModel節點的資料,ASP.NET只會讀取 machine.config中的全域配置資訊,這意味著我們不能使用web.config為不同應用程式配置不同的參數。如果我們要實現應用程式層級的配置,那麼必須使用ThreadPool類中提供的API進行設定。
IO線程池
幾乎所有的非同步功能都依賴於線程池。
通常所說的IO線程池,便是為非同步IO服務的線程池。
同步IO
若無IO線程池,則可能需要通過同步訪問IO(即直接存取IO),其最簡單的方式便是阻塞,如:讀取一個檔案。代碼會等待IO操作成功(或失敗)之後才繼續執行下去,一切都是順序的。
非同步IO
在使用非同步IO時,訪問IO的線程不會被阻塞,邏輯將會繼續下去。作業系統會負責把結果通過某種方法通知我們,一般說來,這種方式是“回呼函數”。非同步IO在執行過程中是不佔用應用程式的線程的,因此我們可以用少量的線程發起大量的IO,所以應用程式的響應能力也可以有所提高。
IOCP
Windows作業系統中有多種非同步IO方式,但是效能最高,伸縮性最好的方式莫過於“IO完成連接埠(I/O Completion Port,IOCP)”,這也是.NET中封裝的唯一一個對IO操作的非同步IO方式。CLR會為每個進程建立一個IOCP(I/O Completion Port)並和Windows作業系統一起維護。
備忘:關於CLR線程的使用與建立,以及CLR線程池與IO線程池是否有關係等,請看《淺談線程池(下):相關實驗及注意事項》中的樣本。
學習來源:
淺談線程池(上):線程池的作用及CLR線程池
淺談線程池(中):獨立線程池的作用及IO線程池
淺談線程池(下):相關實驗及注意事項