上一章我們了解到,由于線程的創(chuàng)建,銷毀都是需要耗費大量資源和時間的,開發(fā)者應(yīng)該非常節(jié)約的使用線程資源。最好的辦法是使用線程池,線程池能夠避免當(dāng)前進行中大量的線程導(dǎo)致操作系統(tǒng)不停的進行線程切換,當(dāng)線程數(shù)量到達了我們設(shè)置的上限,線程會自動排隊等待,當(dāng)線程資源可用時,隊列中的線程任務(wù)會依次執(zhí)行,如果沒有排隊等候的資源,線程會變?yōu)殚e置狀態(tài)。
這種做法可以讓我們不用那么復(fù)雜的去實現(xiàn)創(chuàng)建,重用線程的邏輯,但是也有一些限制,比如由他內(nèi)置的方法,我們不知道什么時候線程池里面的任務(wù)會結(jié)束,也不能獲取線程的返回值。為了解決這些問題,微軟引入了一個新的概念。
引入了Task之后,你可以用如下實現(xiàn)來替代ThreadPool
這些實現(xiàn)都是等價的。Task本身實現(xiàn)了很多ThreadPool不能做的事情。
更多Task同步編程的使用,請參見(還沒寫,先給自己挖個坑O(∩_∩)O)。
ThreadPool.QueueUserWorkItem沒有提供一種簡單的機制來獲取線程的返回值。異步委托解決了這個問題,支持了傳入一系列的參數(shù)。此外,異步委托中沒有處理的異常會很方便的在調(diào)用線程的重新拋出(在調(diào)用EndInvoke的時候),因此不需要顯示的處理。
通過異步委托來執(zhí)行任務(wù)主要分一下幾步:
調(diào)用BeginInvoke不會阻塞當(dāng)前線程,因此你可以在調(diào)用完之后執(zhí)行其他你想要同步的操作
EndInvoke主要做3件事: 1. 等待異步委托完成 2. 接收返回值 3. 把異步線程中未處理的異常在當(dāng)前線程中重新拋出。
你也可以在調(diào)用BeginInvoke的時候指定一個回調(diào)方法,這個方法會在異步委托結(jié)束的時候自動調(diào)用。這樣異步委托就像是一個后臺線程一樣自動執(zhí)行,不需要主線程等待。只需要在BeginInvoke的時候做一些額外的操作即可實現(xiàn)這種操作。
Jeffery在C# via CLR Chapter27中針對線程池的使用給出了一些建議。目前我們允許開發(fā)者來指定一個線程池的最大線程數(shù)。但是事實證明,我們往往不應(yīng)該為一個線程池指定線程的上限,否則可能會出現(xiàn)程序死鎖或者餓死的狀態(tài)。比如你可能設(shè)置了1000個線程,但是某一時刻正好有第1001個線程需要等待所有線程結(jié)束才能執(zhí)行,這種情況如果你限制了線程池線程的個數(shù),就會出現(xiàn)死鎖。從開發(fā)的另一個角度說,你也不應(yīng)該限制一個進程使用多少資源,比如一個進程可以使用多少內(nèi)存,使用多少帶寬.因此雖然目前你可以通過GetMaxThreads, SetMaxThreads,GetMinThreads,SetMinThreads ,GetAvailableThreads來進行線程個數(shù)的限制,但是他仍然不建議大家這樣做。這些限制可能會讓你的程序運行的更慢。
關(guān)于使用Task訪問線程池:
作者:獨上高樓
出處:http://www.survivalescaperooms.com/myPRogram/
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。
新聞熱點
疑難解答