線程的創建和銷毀都要耗費大量的時間,有什么更好的辦法?用線程池!
太多的線程浪費內存資源,有什么更好的辦法?用線程池!
太多線程有損性能,有什么更好的辦法?用線程池!(⊙_⊙)?
線程池是什么?繼前三篇線程基礎之后,我們要來學學線程池了。注意,這些信息相當有用!
為了設計和實現可伸縮的、可響應的和可靠的應用程序或組建,線程池是你必須采用的核心技術。
線程池是CLR的,線程池自動為你管理線程的創建和銷毀,線程池創建的一組線程將為各種任務而重用,極大提高了使用線程的成本,這也就意味着,你的應用程序其實只需要幾個線程即可完成全部工作。
大概的講了一下,來看看線程池的細節:
大家可以想象一下:一個應用程序就好比一個抽屜,抽屜里面放了你分好類的東西,抽屜里面的"某一個東西"就好比這個應用程序的線程集合,這個抽象集合就是一個CLR。假如要搶救財物,你會選擇拿抽屜里的東西還是拿抽屜呢?
好了,有了模型就好介紹CLR了,每個CLR都有它自己的線程池,這個線程池在應用程序域中共享。如果一個進程中加載了多了CLR,那么每個CLR都有它自己的線程池,有點抽象(─.─|||,很難解釋清楚- -。多看幾次,會領會這個意思的。)
CLR在初始化的時候,線程池中沒有是線程的。它的內部,線程池維護着一個操作請求隊列。在應用程序想執行一個異步操作時,就會有發送一個需要調用某個方法的”記錄項“,這個“記錄項”會追加到線程池的隊列中,然后線程池的代碼從這個記錄項中提取記錄,為記錄項分配給一個線程池線程。如果線程池中沒有線程,就創建一個新的線程。
創建線程會消耗一些資源(前面提到過了),當線程完成任務之后,線程不會被銷毀,它從哪里來回哪里去(回到線程池,在那里進入空閑狀態,等待下一次命令),由於線程不會被銷毀,所以不再產生額外的性能損失。
現在疑問來了!如果應用程序發出許多請求,會怎么辦?
線程池會嘗試只用一個線程來服務所有的請求。然而,如果應用程序發出請求的速度超過了線程池處理它們的速度,線程池就會十分人性話的加”雇用兵“,創建額外的線程。到最后,應用程序的有請求都能由少量線程處理,不會存在太多的線程,不會浪費額外的性能。
現在我們又會覺得,如果線程池真的有很多“雇佣兵”了,怎么辦? 不照樣是浪費了嗎?
其實這個已經考慮了,一個“雇佣兵”太久接不到活怎么辦?空閑的線程多了,線程會自己醒來,來終止自己以釋放資源。
不是吧?終止線程也會產生性能損失啊!說好的解決性能損失呢??
哈哈,線程閑的蛋疼了,還有什么性能損失?這表明應用程序已經沒有在做什么事情了,所以這個性能損失,問題不大。
再來扯扯線程池概念,讓大家易於理解。
線程池可以只容納少量線程,從而避免資源浪費;也可以容納更多線程,以利用多處理器,超線程處理器和多核處理器。它能在這兩種不同的狀態之間從容切換。
線程池是啟發式的。只要硬件支持,比如有多個CPU,線程池就會創建更多的線程。如果應用程序的負載減輕,線程池線程就會終結它們自己。
線程池講自己的線程划分為工作者線程和I/O線程。工作者線程是執行異步操作的執行線程,而I/O線程則用於通知你一個異步操作任務已經完成。
寫了一大串概念性的東西,來使用一下線程池吧^_^。
初用線程池,執行簡單的計算限制操作:
1 static void Main(string[] args) 2 { 3 Console.WriteLine("主線程啟動"); 4 ThreadPool.QueueUserWorkItem(StartCode,5); 5 Console.WriteLine("主線程運行到此!"); 6 Thread.Sleep(1000); 7 } 8 9 private static void StartCode(object i) 10 { 11 Console.WriteLine("開始執行子線程...{0}",i); 12 Thread.Sleep(1000);//模擬代碼操作 13 14 15 }
這個和第一篇的那個列子很相似。也很簡單。要說的是,QueueUserWorkItem()中的參數:
必須匹配這個委托,我這個示例是用的第二個方法。
結果就像這樣:
我的是雙核處理器,主線程和子線程是同時運行的。
如果是單核的話,結果可能就不同了,因為這是Windows調試器決定先調度哪個線程控制不了~~~~
這主要介紹線程池,就這么多了。^_^