.NET中的多線程 (二 線程池)

原文鏈接:https://www.cnblogs.com/myprogram/p/4893059.html

https://www.cnblogs.com/myprogram/p/4893059.html

上一章我們瞭解到,由於線程的創建,銷燬都是需要耗費大量資源和時間的,開發者應該非常節約的使用線程資源。最好的辦法是使用線程池,線程池能夠避免當前進行中大量的線程導致操作系統不停的進行線程切換,當線程數量到達了我們設置的上限,線程會自動排隊等待,當線程資源可用時,隊列中的線程任務會依次執行,如果沒有排隊等候的資源,線程會變爲閒置狀態。

使用ThreadPool來訪問線程池

這種做法可以讓我們不用那麼複雜的去實現創建,重用線程的邏輯,但是也有一些限制,比如由他內置的方法,我們不知道什麼時候線程池裏面的任務會結束,也不能獲取線程的返回值。爲了解決這些問題,微軟引入了一個新的概念。

使用Task來訪問線程池

引入了Task之後,你可以用如下實現來替代ThreadPool

這些實現都是等價的。Task本身實現了很多ThreadPool不能做的事情。

使用Task來獲得線程的返回值

 

使用Task來等待線程結束

更多Task同步編程的使用,請參見(還沒寫,先給自己挖個坑O(∩_∩)O)。

異步委託

ThreadPool.QueueUserWorkItem沒有提供一種簡單的機制來獲取線程的返回值。異步委託解決了這個問題,支持了傳入一系列的參數。此外,異步委託中沒有處理的異常會很方便的在調用線程的重新拋出(在調用EndInvoke的時候),因此不需要顯示的處理。

通過異步委託來執行任務主要分一下幾步:

  1. 初始化並聲明一個你想要執行的委託
  2. 在委託上調用BeginInvoke,把返回值保存爲IAsyncResult中

調用BeginInvoke不會阻塞當前線程,因此你可以在調用完之後執行其他你想要同步的操作

  1. 當你需要獲取委託的返回值時,調用EndInvoke方法,把IAsyncResult傳入EndInvoke中

阻塞的方式執行異步委託

 

EndInvoke主要做3件事: 1. 等待異步委託完成 2. 接收返回值 3. 把異步線程中未處理的異常在當前線程中重新拋出。

非阻塞的方式執行異步委託

你也可以在調用BeginInvoke的時候指定一個回調方法,這個方法會在異步委託結束的時候自動調用。這樣異步委託就像是一個後臺線程一樣自動執行,不需要主線程等待。只需要在BeginInvoke的時候做一些額外的操作即可實現這種操作。

關於線程池

Jeffery在C# via CLR Chapter27中針對線程池的使用給出了一些建議。目前我們允許開發者來指定一個線程池的最大線程數。但是事實證明,我們往往不應該爲一個線程池指定線程的上限,否則可能會出現程序死鎖或者餓死的狀態。比如你可能設置了1000個線程,但是某一時刻正好有第1001個線程需要等待所有線程結束才能執行,這種情況如果你限制了線程池線程的個數,就會出現死鎖。從開發的另一個角度說,你也不應該限制一個進程使用多少資源,比如一個進程可以使用多少內存,使用多少帶寬.因此雖然目前你可以通過GetMaxThreads, SetMaxThreads,GetMinThreads,SetMinThreads ,GetAvailableThreads來進行線程個數的限制,但是他仍然不建議大家這樣做。這些限制可能會讓你的程序運行的更慢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章