目錄:
- 為什麼要使用執行緒池
- 簡單的執行緒池操作
- 執行上下文
- 協作式取消
一、為什麼要使用執行緒池:執行緒池概念理解
備註:執行緒池中的執行緒是後臺執行緒。
1、為什麼會有執行緒池?
因為建立執行緒和銷燬執行緒相對來說需要消耗大量的時間和資源。 太多的執行緒會浪費記憶體。
作業系統需要線上程間來回切換,執行緒過多,有損效能。
2、執行緒池是什麼?
執行緒池就是一個可持續性發展的執行緒集合,執行緒池內部維護著一個訊息佇列。
當一條方法名引用追加到執行緒池的佇列中,執行緒池會提取當前項,派發給執行緒池中空閒的執行緒。
3、執行緒池建立執行緒策略?
- 如果執行緒池中沒有執行緒,就建立一個執行緒。
- 如果併發的請求數過多,且請求速度超出執行緒池處理速度,就會建立額外執行緒。
- 如果執行緒完成任務,不會銷燬,會進入空閒狀態,等待下個請求的響應。
- 如果在一定的時間內沒有接收到請求,超度空閒,就會自己醒來,終止自己,釋放資源。
二、簡單的執行緒池操作
我們上面提到過,執行緒池內維護的了一個訊息佇列,方法引用追加到佇列中,執行緒池中的執行緒從佇列中取出等待執行。
[SecuritySafeCritical] public static bool QueueUserWorkItem(WaitCallback callBack);
[SecuritySafeCritical] public static bool QueueUserWorkItem(WaitCallback callBack, object state);
委託:
[ComVisible(true)] public delegate void WaitCallback(object state);
所以,一個是引數為null,一個是需要傳遞實參的委託。要使用以上方式向佇列中新增工作項,其實是將方法引用新增到佇列中
1、我們定義一個符合 WaitCallback 規則的委託 一個引數且沒有返回值
public static void WorkerFun(object flag) { Console.WriteLine("【WorkerFun】 doing ........"); for (int index = 10; index > 0; index--) { Console.WriteLine(" {0}s", index); Thread.Sleep(2000); } Console.WriteLine("【WorkerFun】end."); }
2、我們使用執行緒池進行非同步呼叫
public void Run(string args) { Console.WriteLine("【Main】doing......"); if (ThreadPool.QueueUserWorkItem(WorkerFun)) { Console.WriteLine("Add pool success"); } Console.WriteLine("【Main】sleep 5s.");
Thread.Sleep(5000);
Console.WriteLine("【Main】end.");
}
執行結果:
主執行緒執行完畢,子執行緒自動關閉。所以說,執行緒池中的執行緒都是後臺執行緒,優先順序比較低。
二、執行上下文
1、為什麼要有執行上下文 ?
執行緒在執行程式碼時,會受到上下文的影響。
上下文會從初始執行緒流向輔助執行緒,這樣這整個執行緒使用相同的安全設定和宿主設定。
同樣,輔助執行緒可以使用初始執行緒的邏輯上下文。
namespace System.Threading
//執行上下文 public sealed class ExecutionContext : IDisposable, ISerializable { //從當前執行緒捕獲執行上下文 [SecuritySafeCritical] public static ExecutionContext Capture(); //是否取消了執行上下文的流動 public static bool IsFlowSuppressed(); //恢復執行上下文在非同步執行緒之間的流動 public static void RestoreFlow(); //在當前執行緒上的指定執行上下文中執行某個方法 [SecurityCritical] public static void Run(ExecutionContext executionContext, ContextCallback callback, object state); //取消執行上下文在非同步執行緒之間的流動 [SecurityCritical] public static AsyncFlowControl SuppressFlow(); //建立當前執行上下文的副本 [SecuritySafeCritical] public ExecutionContext CreateCopy(); [SecuritySafeCritical] public void Dispose(); [SecurityCritical] public void GetObjectData(SerializationInfo info, StreamingContext context); }
通過執行上下文我們來控制上下文的流動。
CallContext.LogicalSetData("Name", "sc"); //預設允許上下文進行流動 ThreadPool.QueueUserWorkItem(state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name"))); //現在禁止流動 ExecutionContext.SuppressFlow(); ThreadPool.QueueUserWorkItem(state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name"))); //恢復流動 ExecutionContext.RestoreFlow(); Console.ReadKey();
執行:第一行允許流動;第二行禁止流動
Name=sc
Name=
三、協作式取消和超時
需要取消的模式必須顯示支援取消
//通知 System.Threading.CancellationToken,告知其應被取消 public sealed class CancellationTokenSource : IDisposable
CancellationTokenSource 管理 著取消相關的狀態.
所謂協作式,首先我自己要支援取消,接收訊號後任務終止。
private static void Count(System.Threading.CancellationToken token, int countto) { for (int count = 0; count < countto; count++) { Console.WriteLine("index:{0}", count); if (token.IsCancellationRequested) { Console.WriteLine("Count is cancelled {0}",count); break; } } }
主執行緒中,接收協作式取消命令,子執行緒檢測到訊號後,主動停止。
public void Run(string args) { System.Threading.CancellationTokenSource cts = new CancellationTokenSource(); //開啟執行緒 ThreadPool.QueueUserWorkItem(state => Count(cts.Token, 10000000)); Console.WriteLine("Press <Enter> to cancel the operation"); Console.ReadLine(); cts.Cancel(); Console.ReadLine(); }
執行結果:主執行緒發出回車訊號,子執行緒檢測到訊號後結束任務。