本筆記摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/18/ThreadPool.html,記錄一下學習程序以備后續查用,
一、執行緒池基礎
首先,創建和銷毀執行緒是一個要耗費大量時間的程序,其次,太多的執行緒也會浪費記憶體資源,所以通過Thread類來創建過多的執行緒反而有損于性能,為了改善這樣
的問題 ,.NET中就引入了執行緒池,
執行緒池形象的表示就是存放應用程式中使用的執行緒的一個集合(就是放執行緒的地方,這樣執行緒都放在一個地方就好管理了),
CLR初始化時,執行緒池中是沒有執行緒的,在內部, 執行緒池維護了一個操作請求佇列,當應用程式想執行一個異步操作時,就呼叫一個方法,將一個任務放到執行緒池
的佇列中,執行緒池代碼從佇列中提取任務,將這個任務委派給一個執行緒池執行緒去執行,當執行緒池執行緒完成任務時,執行緒不會被銷毀,而是回傳到執行緒池中,等待回應另
一個請求,由于執行緒不被銷毀, 這樣就可以避免因為創建執行緒所產生的性能損失,
MSDN表述:
“執行緒池經常用在服務器應用程式中,每一個新進來的需求被分配給一個執行緒池中的執行緒,這樣該需求能被異步的執行,沒有阻礙主執行緒或推遲后繼需求的處理,”
注意:通過執行緒池創建的執行緒默認為后臺執行緒,優先級默認為Normal,
二、通過執行緒池的作業者執行緒實作異步
2.1創建作業者執行緒的方法
public static bool QueueUserWorkItem (WaitCallback callback);
public static bool QueueUserWorkItem(WaitCallback callback, Object state);
這兩個方法向執行緒池的佇列添加一個作業項(work item)以及一個可選的狀態資料,然后,這兩個方法就會立即回傳,
作業項其實就是由callback引數標識的一個方法,該方法將由執行緒池執行緒執行,同時寫的回呼方法必須匹配System.Threading.WaitCallback委托型別,定義為:
public delegate void WaitCallback(Object state);
下面演示如何通過執行緒池執行緒來實作異步呼叫:
class Program { static void Main(string[] args) { #region 通過執行緒池的作業者執行緒實作異步 //設定執行緒池中作業者執行緒最大數量為1000,I/O執行緒最大數量為1000, ThreadPool.SetMaxThreads(1000, 1000); Console.WriteLine("Main thread: queue an asynchronous method."); PrintMessage("Main thread start."); //把作業項添加到佇列中,此時執行緒池會用作業者執行緒去執行回呼方法, ThreadPool.QueueUserWorkItem(AsyncMethod); Console.Read(); #endregion } /// <summary> /// 列印執行緒池資訊 /// </summary> /// <param name="data"></param> private static void PrintMessage(string data) { //獲得執行緒池中可用的作業者執行緒數量及I/O執行緒數量 ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n", data, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground.ToString(), workThreadNumber.ToString(), ioThreadNumber.ToString()); } /// <summary> /// 異步方法:必須匹配WaitCallback委托 /// </summary> /// <param name="state"></param> private static void AsyncMethod(object state) { Thread.Sleep(1000); PrintMessage("Asynchoronous method."); Console.WriteLine("Asynchoronous thread has worked."); } }
運行結果如下:

從結果中可以看出,執行緒池中的可用的作業者執行緒少了一個,用去執行回呼方法了,
ThreadPool.QueueUserWorkItem(WaitCallback callback,Object state) 方法可以把object物件作為引數傳送到回呼函式中,使用方法與
ThreadPool.QueueUserWorkItem(WaitCallback callback)類似,這里就不列出了,
2.2 協作式取消
.NET Framework提供了取消操作的模式, 這個模式是協作式的,為了取消一個操作,首先必須創建一個System.Threading.CancellationTokenSource物件,
下面代碼演示協作式取消的使用,主要實作當用戶在控制臺敲下回車鍵后就停止數數方法,
class Program { static void Main(string[] args) { #region 協作式取消 ThreadPool.SetMaxThreads(1000, 1000); Console.WriteLine("Main thread run."); PrintMessage("Start"); Run(); Console.ReadKey(); #endregion } /// <summary> /// 列印執行緒池資訊 /// </summary> /// <param name="data"></param> private static void PrintMessage(string data) { //獲得執行緒池中可用的作業者執行緒數量及I/O執行緒數量 ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n", data, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground.ToString(), workThreadNumber.ToString(), ioThreadNumber.ToString()); } /// <summary> /// 運行作業者執行緒(包含協作式取消) /// </summary> private static void Run() { CancellationTokenSource cts = new CancellationTokenSource(); //這里是用Lambda運算式的寫法,效果一樣, //ThreadPool.QueueUserWorkItem(obj => Count(cts.Token, 1000)); ThreadPool.QueueUserWorkItem(Callback, cts.Token); Console.WriteLine("Press enter key to cancel the operation.\n"); Console.ReadLine(); //傳達取消請求 cts.Cancel(); } /// <summary> /// 回呼函式 /// </summary> /// <param name="state"></param> private static void Callback(object state) { Thread.Sleep(1000); PrintMessage("Asynchoronous method start."); CancellationToken token = (CancellationToken)state; Count(token, 1000); } /// <summary> /// 數數 /// </summary> /// <param name="token"></param> /// <param name="countTo"></param> private static void Count(CancellationToken token, int countTo) { for (int i = 1; i <= countTo; i++) { if (token.IsCancellationRequested) { Console.WriteLine("Count is canceled."); break; } Console.WriteLine(i); Thread.Sleep(300); } Console.WriteLine("Count has done."); } }
運行結果如下:

三、使用委托實作異步
涉及術語解釋--異步編程模型:
APM 異步編程模型(Asynchronous Programming Model)
EAP 基于事件的異步編程模式(Event-based Asynchronous Pattern)
TAP 基于任務的異步編程模式(Task-based Asynchronous Pattern)
通過呼叫ThreadPool的QueueUserWorkItem方法來來啟動作業者執行緒非常方便,但委托WaitCallback指向的是帶有一個引數的無回傳值的方法,如果我們實際操作中
需要有回傳值,或者需要帶有多個引數, 這時通過這樣的方式就難以實作了, 為了解決這樣的問題,我們可以通過委托來建立作業這執行緒,
下面代碼演示使用委托實作異步:
class Program { //使用委托實作異步,是使用了異步編程模型APM, private delegate string ThreadDelegate(); static void Main(string[] args) { #region 使用委托實作異步 ThreadPool.SetMaxThreads(1000, 1000); PrintMessage("Main thread start."); //實體化委托 ThreadDelegate threadDelegate = new ThreadDelegate(AsyncMethod); //異步呼叫委托 IAsyncResult result = threadDelegate.BeginInvoke(null, null); //獲取結果并列印 string returnData =https://www.cnblogs.com/atomy/p/ threadDelegate.EndInvoke(result); Console.WriteLine(returnData); Console.ReadLine(); #endregion } /// <summary> /// 列印執行緒池資訊 /// </summary> /// <param name="data"></param> private static void PrintMessage(string data) { //獲得執行緒池中可用的作業者執行緒數量及I/O執行緒數量 ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n", data, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground.ToString(), workThreadNumber.ToString(), ioThreadNumber.ToString()); } /// <summary> /// 異步方法 /// </summary> /// <returns></returns> private static string AsyncMethod() { Thread.Sleep(1000); PrintMessage("Asynchoronous method."); return "Method has completed."; } }
運行結果如下:

四、任務
同樣,任務的引入也是為了解決通過ThreadPool.QueueUserWorkItem中限制的問題,
4.1 使用任務來實作異步
class Program { static void Main(string[] args) { #region 使用任務實作異步 ThreadPool.SetMaxThreads(1000, 1000); PrintMessage("Main thread start."); //呼叫建構式創建Task物件 Task<int> task = new Task<int>(n => AsyncMethod((int)n), 10); //啟動任務 task.Start(); //等待任務完成 task.Wait(); Console.WriteLine("The method result is: " + task.Result); Console.ReadLine(); #endregion } /// <summary> /// 列印執行緒池資訊 /// </summary> /// <param name="data"></param> private static void PrintMessage(string data) { //獲得執行緒池中可用的作業者執行緒數量及I/O執行緒數量 ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n", data, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground.ToString(), workThreadNumber.ToString(), ioThreadNumber.ToString()); } /// <summary> /// 異步方法 /// </summary> /// <param name="n"></param> /// <returns></returns> private static int AsyncMethod(int n) { Thread.Sleep(1000); PrintMessage("Asynchoronous method."); int sum = 0; for (int i = 1; i < n; i++) { //運算溢位檢查 checked { sum += i; } } return sum; } }
運行結果如下:

4.2 取消任務
如果要取消任務, 同樣也可以CancellationTokenSource物件來取消,
下面代碼演示取消一個任務:
class Program { static void Main(string[] args) { #region 取消任務 ThreadPool.SetMaxThreads(1000, 1000); PrintMessage("Main thread start."); CancellationTokenSource cts = new CancellationTokenSource(); //呼叫建構式創建Task物件,將一個CancellationToken傳給Task構造器從而使Task和CancellationToken關聯起來, Task<int> task = new Task<int>(n => AsyncMethod(cts.Token, (int)n), 10); //啟動任務 task.Start(); //延遲取消任務 Thread.Sleep(3000); //取消任務 cts.Cancel(); Console.WriteLine("The method result is: " + task.Result); Console.ReadLine(); #endregion } /// <summary> /// 列印執行緒池資訊 /// </summary> /// <param name="data"></param> private static void PrintMessage(string data) { //獲得執行緒池中可用的作業者執行緒數量及I/O執行緒數量 ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n", data, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground.ToString(), workThreadNumber.ToString(), ioThreadNumber.ToString()); } /// <summary> /// 異步方法 /// </summary> /// <param name="ct"></param> /// <param name="n"></param> /// <returns></returns> private static int AsyncMethod(CancellationToken ct, int n) { Thread.Sleep(1000); PrintMessage("Asynchoronous method."); int sum = 0; try { for (int i = 1; i < n; i++) { //當CancellationTokenSource物件呼叫Cancel方法時,就會引起OperationCanceledException例外, //通過呼叫CancellationToken的ThrowIfCancellationRequested方法來定時檢查操作是否已經取消, //這個方法和CancellationToken的IsCancellationRequested屬性類似, ct.ThrowIfCancellationRequested(); Thread.Sleep(500); //運算溢位檢查 checked { sum += i; } } } catch (Exception e) { Console.WriteLine("Exception is:" + e.GetType().Name); Console.WriteLine("Operation is canceled."); } return sum; } }
運算結果如下:

4.3 使用任務工廠實作異步操作
同樣也可以通過任務工廠TaskFactory型別來實作異步操作,
class Program { static void Main(string[] args) { #region 使用任務工廠實作異步 ThreadPool.SetMaxThreads(1000, 1000); Task.Factory.StartNew(() => PrintMessage("Main thread.")); Console.Read(); #endregion } /// <summary> /// 列印執行緒池資訊 /// </summary> /// <param name="data"></param> private static void PrintMessage(string data) { //獲得執行緒池中可用的作業者執行緒數量及I/O執行緒數量 ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n", data, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground.ToString(), workThreadNumber.ToString(), ioThreadNumber.ToString()); } }
運行結果如下:
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/96170.html
標籤:C#
