多執行緒系列(三):執行緒池基礎

K戰神發表於2018-03-28

目錄:

  • 為什麼要使用執行緒池
  • 簡單的執行緒池操作
  • 執行上下文
  • 協作式取消

一、為什麼要使用執行緒池:執行緒池概念理解

備註:執行緒池中的執行緒是後臺執行緒。

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();
}

 執行結果:主執行緒發出回車訊號,子執行緒檢測到訊號後結束任務。

 

相關文章