.NET中的線程池是受CLR管理的,TheadTool類有一個QueueUserWorkItem靜態方法,這個靜態方法接受一個委托,代表用戶自定義的一個非同步操作,在這個方法被調用之後,委托會進入到內部隊列中,如果池中沒有線程,則創建一個工作線程,把第一個委托放入工作線程。如果繼續放入委托,則池創建新... ...
創建多線程操作是非常昂貴的,所以每個運行時間非常短的操作,創建多線程進行操作,可能並不能提高效率,反而降低了效率。
如果你有非常多的執行時間非常短的操作,那麼適合作用線程池來提高效率,而不是自行創建多線程。
線程池,就是我們先分配一些資源到池子里,當我們需要使用時,則從池子中獲取,用完了,再放回池子里。
.NET中的線程池是受CLR管理的,TheadTool類有一個QueueUserWorkItem靜態方法,這個靜態方法接受一個委托,代表用戶自定義的一個非同步操作,在這個方法被調用之後,委托會進入到內部隊列中,如果池中沒有線程,則創建一個工作線程,把第一個委托放入工作線程。如果繼續放入委托,則池創建新的工作線程,直到工作線程數量達到上限。這時再放入委托,則不會創建新的工作線程,而是在隊列中等待,直到有空閑的工作線程。
當線程池中所有操作都完成,而且沒有新任務操作時,線程池會釋放長時間不用的資源。
註意:放入線程池中的操作需要的時間要短,不要把需要長時間運行的操作放入線程池中,或阻塞工作線程。這將導致性能問題和非常難以調用的問題。
在ASP.NET中使用線程池要當心,ASP.NET中的線程池是一個共用線程池,如果線程池中的工作線程都用完了,則會造成WEB伺服器對正常的HTTP請求無法提供服務。
一、 線程池中調用委托
1.代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ThreadPoolDemo { public delegate string ThreadPoolRun(out int threadId); class Program { static void Main(string[] args) { Console.WriteLine("開始測試線程池-委托。。。"); int threadId = 0; ThreadPoolRun poolDele = RunThread; var t = new Thread(() => RunThread(out threadId)); t.Start(); t.Join(); Console.WriteLine("線程ID {0} ",threadId); IAsyncResult r = poolDele.BeginInvoke(out threadId, Callback, "線上程池中同步調用回調函數"); string result = poolDele.EndInvoke(out threadId, r); Console.WriteLine("線程池中工作線程ID :{0}", threadId); Console.WriteLine("返回結果:{0}",result); Thread.Sleep(2000); Console.Read(); } private static void Callback(IAsyncResult r) { Console.WriteLine("開始調用回調函數。。。"); Console.WriteLine("回調函數此時的狀態 :{0}",r.AsyncState); Console.WriteLine("調用此回調函數的線程是否線上程池 :{0}", Thread.CurrentThread.IsThreadPoolThread); Console.WriteLine("調用此回調函數的線程線上程池在的ID :{0}", Thread.CurrentThread.ManagedThreadId); } private static string RunThread(out int threadId) { Console.WriteLine("開始工作。。。"); Console.WriteLine("調用此回調函數的線程是否線上程池 :{0}", Thread.CurrentThread.IsThreadPoolThread); Thread.Sleep(TimeSpan.FromSeconds(2)); threadId = Thread.CurrentThread.ManagedThreadId; return string.Format("此線程線上程池在的ID :{0}", threadId); } } }
2.程式執行結果如下圖。
上面的程式運行時,我們首先創建線程來執行委托操作,然後調用委托的BeginInvoke來執行回調方法,這個回調函數會在非同步操作完成之後會被調用,並且會把一個自定義的值傳給這個回調函數,最後我們會得到一個實現了IAsyncResult介面的result對象,當線程池的工作線程在進行工作時,允許我們繼續其他操作。我們可以輪詢result對象的IsCompleted屬性,確定操作是否完成。也可以調用EndInvoke將IAsyncResult傳給委托參數。
二、 線程池中放入非同步操作
1.代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ThreadPoolDemo { class Program { static void Main(string[] args) { Console.WriteLine("開始測試線程池-QueueUserWorkItem。。。"); const int x = 1; const int y = 2; string workState = "工作狀態 2"; ThreadPool.QueueUserWorkItem(AsyncOper); Thread.Sleep(1000); ThreadPool.QueueUserWorkItem(AsyncOper,"同步狀態"); Thread.Sleep(1000); ThreadPool.QueueUserWorkItem(status => { Console.WriteLine("操作狀態 {0} ", status); Console.WriteLine("線程池中工作線程ID :{0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromSeconds(2)); },"工作狀態"); ThreadPool.QueueUserWorkItem(_ => { Console.WriteLine("操作結果x+y= {0} ,{1}", x+y,workState); Console.WriteLine("線程池中工作線程ID :{0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromSeconds(2)); }, "工作狀態"); Thread.Sleep(2000); Console.Read(); } private static void AsyncOper(object status) { Console.WriteLine("操作狀態 :{0} ",status??"null"); Console.WriteLine("工作線程線上程池在的ID :{0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(2000); } } }
2.執行結果如下。程式執行了兩次。
程式首先定義了一個AsyncOper方法,然後使用QueueUserWorkItem將這個方法放入線程池中,然後再次放入一個AsyncOper方法,不過這次給方法調用傳一個對象。
代碼中的調用Thread.sleep方法,是為了讓線程池中的工作線程為新操作重用。請註意列印出來的ThradId,如果ThreadID一樣則證明兩個操作重用了同一個工作線程。