程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> .NET 4並行(多核)編程系列之四 Task的休眠

.NET 4並行(多核)編程系列之四 Task的休眠

編輯:關於.NET

前言:之前的幾篇文章斷斷續續的介紹了Task的一些功能:創建,取消。本篇介紹Task的休眠,本篇的內容比較的少。

本篇的議題如下:

1.Task的休眠。

1.Task的休眠

有時候,我們常常希望一個Task在等待一段時間之後再運行,也就有點類似之前多線程編程中的Sleep。我們可以設置一個Task休眠多長時間,當這個時間過了,Task就自動的喚醒接著運行。

下面就講講休眠的方法:

a.使用CancellationToken的Wait Handle:

a)在.NET 4並行編程中,讓一個Task休眠的最好的方式就是使用CancellationToken的等待操作(Wait Handle)。而且操作起來也很簡單:首先創建一個CancellationTokenSource的實例,然後通過這個實例的Token屬性得到一個CancellationToken的實例,然後在用CancellationToken的WaitHandle屬性,然後調用這個這個屬性的WaitOne()方法。其實在之前講述”Task的取消”一文中就已經使用過。

b)WaitOne()方法有很多的重載方法來提供更多的功能,例如可以傳入一個int的整數,表明要休眠多長的時間,單位是微秒,也可以傳入一個TimeSpan的值。如果調用了CancellationToken的Cancel()方法,那麼休眠就立刻結束。就是因為這個原因,我們之前的文章講過,WaitOne()可以作為檢測Task是否被取消的一個方案

下面來看一段示例代碼:

代碼

static void Main(string[] args)
         {
             // create the cancellation token source
             CancellationTokenSource tokenSource = new CancellationTokenSource();
             // create the cancellation token
             CancellationToken token = tokenSource.Token;
             // create the first task, which we will let run fully
             Task task1 = new Task(()=>
             {
                 for (int i = 0; i < Int32.MaxValue; i++)
                 {
                     // put the task to sleep for 10 seconds
                     bool cancelled = token.WaitHandle.WaitOne(10000);
                     // print out a message
                     Console.WriteLine("Task 1 - Int value {0}.Cancelled? {1}",
                     i, cancelled);
                     // check to see if we have been cancelled
                     if (cancelled)
                     {
                         throw new OperationCanceledException(token);
                     }
                 }
             }, token);
             // start task
             task1.Start();
             // wait for input before exiting
             Console.WriteLine("Press enter to cancel token.");
             Console.ReadLine();
             // cancel the token
             tokenSource.Cancel();
             // wait for input before exiting
             Console.WriteLine("Main method complete.Press enter to finish.");
             Console.ReadLine();
         }

在上面的代碼中,task在休眠了10秒鐘之後就打印出一條信息。在例子中,在我們敲一下鍵盤之後,CancellationToken就會被Cancel,此時休眠就停止了,task重新喚醒,只不過是這個task將會被cancel掉。

有一點要注意:WaitOne()方法只有在設定的時間間隔到了,或者Cancel方法被調用,此時task才會被喚醒。如果如果cancel()方法被調用而導致task被喚醒,那麼CancellationToken.WaitHandle.WaitOne()方法就會返回true,如果是因為設定的時間到了而導致task喚醒,那麼CancellationToken.WaitHandle.WaitOne()方法返回false。

b.task休眠的第二種方法:使用傳統的Sleep。

我們現在已經知道了:其實TPL(並行編程)的底層還是基於.NET的線程機制的。所以還是可以用傳統的線程技術來使得一個task休眠:調用靜態方法—Thread.Sleep(),並且可以傳入一個int類型的參數,表示要休眠多長時間。

代碼

static void Main(string[] args)
         {
             // create the cancellation token source
             CancellationTokenSource tokenSource = new CancellationTokenSource();
             // create the cancellation token
             CancellationToken token = tokenSource.Token;
             // create the first task, which we will let run fully
             Task task1 = new Task(()=>
             {
                 for (int i = 0; i < Int32.MaxValue; i++)
                 {
                     // put the task to sleep for 10 seconds
                     Thread.Sleep(10000);
                     // print out a message
                     Console.WriteLine("Task 1 - Int value {0}", i);
                     // check for task cancellation
                     token.ThrowIfCancellationRequested();
                 }
             }, token);
             // start task
             task1.Start();
             // wait for input before exiting
             Console.WriteLine("Press enter to cancel token.");
             Console.ReadLine();
             // cancel the token
             tokenSource.Cancel();
             // wait for input before exiting
             Console.WriteLine("Main method complete.Press enter to finish.");
             Console.ReadLine();
         }

這種方法和之前第一種方法最大的區別就是:使用Thread.Sleep()之後,然後再調用token的cancel方法,task不會立即就被cancel,這主要是因為Thread.Sleep()將會一直阻塞線程,直到達到了設定的時間,這之後,再去check task時候被cancel了。舉個例子,假設再task方法體內調用Thread.Sleep(100000)方法來休眠task,然後再後面的代碼中調用token.Cancel()方法,此時處於並行編程內部機制不會去檢測task是否已經發出了cancel請求,而是一直休眠,直到時間超過了100000微秒。如果采用的是之前的第一種休眠方法,那麼不管WaitOne()中設置了多長的時間,只要token.Cancel()被調用,那麼task就像內部的Scheduler發出了cancel的請求,而且task會被cancel。

c.第三種休眠方法:自旋等待.

這種方法也是值得推薦的。之前的兩種方法,當他們使得task休眠的時候,這些task已經從Scheduler的管理中退出來了,不被再內部的Scheduler管理(Scheduler,這裡只是簡單的提下,因為後面的文章會詳細講述,這裡只要知道Scheduler是負責管理線程的),因為休眠的task已經不被Scheduler管理了,所以Scheduler必須做一些工作去決定下一步是哪個線程要運行,並且啟動它。為了避免Scheduler做那些工作,我們可以采用自旋等待:此時這個休眠的task所對應的線程不會從Scheduler中退出,這個task會把自己和CPU的輪轉關聯起來,我們還是用代碼示例講解吧。

代碼

static void Main(string[] args)
         {
             // create the cancellation token source
             CancellationTokenSource tokenSource = new CancellationTokenSource();
             // create the cancellation token
             CancellationToken token = tokenSource.Token;
             // create the first task, which we will let run fully
             Task task1 = new Task(()=>
             {
                 for (int i = 0; i < Int32.MaxValue; i++)
                 {
                     // put the task to sleep for 10 seconds
                     Thread.SpinWait(10000);
                     // print out a message
                     Console.WriteLine("Task 1 - Int value {0}", i);
                     // check for task cancellation
                     token.ThrowIfCancellationRequested();
                 }
             }, token);
             // start task
             task1.Start();
             // wait for input before exiting
             Console.WriteLine("Press enter to cancel token.");
             Console.ReadLine();
             // cancel the token
             tokenSource.Cancel();
             // wait for input before exiting
             Console.WriteLine("Main method complete.Press enter to finish.");
             Console.ReadLine();
         }

代碼中我們在Thread.SpinWait()方法中傳入一個整數,這個整數就表示CPU時間片輪轉的次數,至於要等待多長的時間,這個就和計算機有關了,不同的計算機,CPU的輪轉時間不一樣。自旋等待的方法常常於獲得同步鎖,後續會講解。使用自旋等待會一直占用CPU,而且也會消耗CPU的資源,更大的問題就是這個方法會影響Scheduler的運作。

今天就寫道這裡:後續文章將會逐一講解:Task的等待完成操作,Task中的異常處理,獲取Task的狀態,執行Lazily Task,常見問題解決方案

出處:http://www.cnblogs.com/yanyangtian

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved