天天看點

《C#多線程程式設計實戰(原書第2版)》——第3章 使用線程池 3.1 簡介

本節書摘來自華章出版社《c#多線程程式設計實戰(原書第2版)》一書中的第3章,第3.1節,作者(美)易格恩·阿格佛溫(eugene agafonov),黃博文 黃輝蘭 譯,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

在本章中,我們将描述多線程中使用共享資源的常用技術。你将學到以下内容:

線上程池中調用委托

向線程池中放入異步操作

線程池與并行度

實作一個取消選項

線上程池中使用等待事件處理器及逾時

使用計時器

使用backgroundworker元件

在之前的章節中我們讨論了建立線程和線程協作的幾種方式。現在考慮另一種情況,即隻花費極少的時間來完成建立很多異步操作。正如在第1章的簡介小節中讨論過的一樣,建立線程是昂貴的操作,是以為每個短暫的異步操作建立線程會産生顯著的開銷。

為了解決該問題,有一個常用的方式叫作池(pooling)。線程池可以成功地适應于任何需要大量短暫的開銷大的資源的情形。我們事先配置設定一定的資源,将這些資源放入到資源池。每次需要新的資源,隻需從池中擷取一個,而不用建立一個新的。當該資源不再被使用時,就将其傳回到池中。

.net線程池是該概念的一種實作。通過system.threading.threadpool類型可以使用線程池。線程池是受.net通用語言運作時(common language runtime,簡稱clr)管理的。這意味着每個clr都有一個線程池執行個體。threadpool類型擁有一個queueuserworkitem靜态方法。該靜态方法接受一個委托,代表使用者自定義的一個異步操作。在該方法被調用後,委托會進入到内部隊列中。如果池中沒有任何線程,将建立一個新的工作者線程(worker thread)并将隊列中第一個委托放入到該工作者線程中。

如果想線程池中放入新的操作,當之前的所有操作完成後,很可能隻需重用一個線程來執行這些新的操作。然而,如果放置新的操作過快,線程池将建立更多的線程來執行這些操作。建立太多的線程是有限制的,在這種情況下新的操作将在隊列中等待直到線程池中的工作者線程有能力來執行它們。

當停止向線程池中放置新操作時,線程池最終會删除一定時間後過期的不再使用的線程。這将釋放所有那些不再需要的系統資源。

我想再次強調線程池的用途是執行運作時間短的操作。使用線程池可以減少并行度耗費及節省作業系統資源。我們隻使用較少的線程,但是以比平常更慢的速度來執行異步操作,使用一定數量的可用的工作者線程批量處理這些操作。如果操作能快速地完成則比較适用線程池,但是執行長時間運作的計算密集型操作則會降低性能。

另一個重要事情是在asp.net應用程式中使用線程池時要相當小心。asp.net基礎設施使用自己的線程池,如果線上程池中浪費所有的工作者線程,web伺服器将不能夠服務新的請求。在asp.net中隻推薦使用輸入/輸出密集型的異步操作,因為其使用了一個不同的方式,叫做i/o線程。我們将在第9章中讨論i/o線程。

在本章中,我們将學習使用線程池來執行異步操作。本章将覆寫将操作放入線程池的不同方式,以及如何取消一個操作,并防止其長時間運作。