新聞中心
查看本系列其他文章,請參看

專注于為中小企業(yè)提供網(wǎng)站制作、成都網(wǎng)站設(shè)計服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)盈江免費做網(wǎng)站提供優(yōu)質(zhì)的服務。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了成百上千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴充和轉(zhuǎn)變。
[[11751]]
本篇的議題如下:
1.Task的休眠。
1. Task的休眠
有時候,我們常常希望一個Task在等待一段時間之后再運行,也就有點類似之前多線程編程中的Sleep。我們可以設(shè)置一個Task休眠多長時間,當這個時間過了,Task就自動的喚醒接著運行。
下面就講講休眠的方法:
a.使用CancellationToken的Wait Handle:
a) 在.NET 4并行編程中,讓一個Task休眠的最好的方式就是使用CancellationToken的等待操作(Wait Handle)。而且操作起來也很簡單:首先創(chuàng)建一個CancellationTokenSource的實例,然后通過這個實例的Token屬性得到一個CancellationToken的實例,然后在用CancellationToken的WaitHandle屬性,然后調(diào)用這個這個屬性的WaitOne()方法。其實在之前講述”Task的取消”一文中就已經(jīng)使用過。
b) WaitOne()方法有很多的重載方法來提供更多的功能,例如可以傳入一個int的整數(shù),表明要休眠多長的時間,單位是微秒,也可以傳入一個TimeSpan的值。如果調(diào)用了CancellationToken的Cancel()方法,那么休眠就立刻結(jié)束。就是因為這個原因,我們之前的文章講過,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()方法只有在設(shè)定的時間間隔到了,或者Cancel方法被調(diào)用,此時task才會被喚醒。如果如果cancel()方法被調(diào)用而導致task被喚醒,那么CancellationToken.WaitHandle.WaitOne()方法就會返回true,如果是因為設(shè)定的時間到了而導致task喚醒,那么CancellationToken.WaitHandle.WaitOne()方法返回false。
b.task休眠的第二種方法:使用傳統(tǒng)的Sleep。
我們現(xiàn)在已經(jīng)知道了:其實TPL(并行編程)的底層還是基于.NET的線程機制的。所以還是可以用傳統(tǒng)的線程技術(shù)來使得一個task休眠:調(diào)用靜態(tài)方法—Thread.Sleep(),并且可以傳入一個int類型的參數(shù),表示要休眠多長時間。
代碼
- 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();
- }
這種方法和之前第一種方法最大的區(qū)別就是:使用Thread.Sleep()之后,然后再調(diào)用token的cancel方法,task不會立即就被cancel,這主要是因為Thread.Sleep()將會一直阻塞線程,直到達到了設(shè)定的時間,這之后,再去check task時候被cancel了。舉個例子,假設(shè)再task方法體內(nèi)調(diào)用Thread.Sleep(100000)方法來休眠task,然后再后面的代碼中調(diào)用token.Cancel()方法,此時處于并行編程內(nèi)部機制不會去檢測task是否已經(jīng)發(fā)出了cancel請求,而是一直休眠,直到時間超過了100000微秒。如果采用的是之前的第一種休眠方法,那么不管WaitOne()中設(shè)置了多長的時間,只要token.Cancel()被調(diào)用,那么task就像內(nèi)部的Scheduler發(fā)出了cancel的請求,而且task會被cancel。
c.第三種休眠方法:自旋等待.
這種方法也是值得推薦的。之前的兩種方法,當他們使得task休眠的時候,這些task已經(jīng)從Scheduler的管理中退出來了,不被再內(nèi)部的Scheduler管理(Scheduler,這里只是簡單的提下,因為后面的文章會詳細講述,這里只要知道Scheduler是負責管理線程的),因為休眠的task已經(jīng)不被Scheduler管理了,所以Scheduler必須做一些工作去決定下一步是哪個線程要運行,并且啟動它。為了避免Scheduler做那些工作,我們可以采用自旋等待:此時這個休眠的task所對應的線程不會從Scheduler中退出,這個task會把自己和CPU的輪轉(zhuǎn)關(guān)聯(lián)起來,我們還是用代碼示例講解吧。
代碼
- 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()方法中傳入一個整數(shù),這個整數(shù)就表示CPU時間片輪轉(zhuǎn)的次數(shù),至于要等待多長的時間,這個就和計算機有關(guān)了,不同的計算機,CPU的輪轉(zhuǎn)時間不一樣。自旋等待的方法常常于獲得同步鎖,后續(xù)會講解。使用自旋等待會一直占用CPU,而且也會消耗CPU的資源,更大的問題就是這個方法會影響Scheduler的運作。
今天就寫道這里:后續(xù)文章將會逐一講解:Task的等待完成操作,Task中的異常處理,獲取Task的狀態(tài),執(zhí)行Lazily Task,常見問題解決方案。
本文名稱:.NET4并行編程入門之Task的休眠
分享鏈接:http://fisionsoft.com.cn/article/cccgcig.html


咨詢
建站咨詢
