https://blog.csdn.net/younghaiqing/article/details/81455410
1.Task類介紹:
Task 類的表示單個操作不返回一個值,通常以異步方式執行。 Task 對象是一個的中心思想 基於任務的異步模式 首次引入.NET Framework 4 中。 因為由執行工作 Task 對象通常以異步方式執行在線程池線程上而不是以同步方式在主應用程序線程,您可以使用 Status 屬性,以及 IsCanceled, ,IsCompleted, ,和 IsFaulted 屬性,以確定任務的狀態。 大多數情況下,lambda 表達式用於指定的任務是執行的工作。
對於返回值的操作,您使用 Task 類。
任務Task和線程Thread的區別:
1、任務是架構在線程之上的,也就是說任務最終還是要拋給線程去執行。
2、任務跟線程不是一對一的關系,比如開10個任務並不是說會開10個線程,這一點任務有點類似線程池,但是任務相比線程池有很小的開銷和精確的控制。
Task和Thread一樣,位於System.Threading命名空間下!
一、創建Task
Task 類還提供了構造函數對任務進行初始化,但的未計划的執行。 出於性能原因, Task.Run 或 TaskFactory.StartNew(工廠創建) 方法是用於創建和計划計算的任務的首選的機制,但對於創建和計划必須分開的方案,您可以使用的構造函數(new一個出來),然后調用 Task.Start 方法來計划任務,以在稍后某個時間執行。
//第一種創建方式,直接實例化:必須手動去Start var task1 = new Task(() => { //TODO you code }); task1.Start(); //第二種創建方式,工廠創建,直接執行 var task2 = Task.Factory.StartNew(() => { //TODO you code });
二、Task的簡略生命周期:
方法名 | 說明 |
---|---|
Created | 表示默認初始化任務,但是“工廠創建的”實例直接跳過。 |
WaitingToRun | 這種狀態表示等待任務調度器分配線程給任務執行。 |
RanToCompletion | 任務執行完畢。 |
//查看Task中的狀態 var task1 = new Task(() => { Console.WriteLine("Begin"); System.Threading.Thread.Sleep(2000); Console.WriteLine("Finish"); }); Console.WriteLine("Before start:" + task1.Status); task1.Start(); Console.WriteLine("After start:" + task1.Status); task1.Wait(); Console.WriteLine("After Finish:" + task1.Status); Console.Read();
三、Task的任務控制:Task最吸引人的地方就是他的任務控制了,你可以很好的控制task的執行順序,讓多個task有序的工作
方法名 | 說明 |
---|---|
Task.Wait | task1.Wait();就是等待任務執行(task1)完成,task1的狀態變為Completed。 |
Task.WaitAll | 待所有的任務都執行完成: |
Task.WaitAny | 發同Task.WaitAll,就是等待任何一個任務完成就繼續向下執行 |
Task.ContinueWith | 第一個Task完成后自動啟動下一個Task,實現Task的延續 |
CancellationTokenSource | 通過cancellation的tokens來取消一個Task。 |
下面詳細介紹一下上面的幾個方法:
1、Task.Wait
task1.Wait();就是等待任務執行(task1)完成,task1的狀態變為Completed。
2、Task.WaitAll
看字面意思就知道,就是等待所有的任務都執行完成:
{
Task.WaitAll(task,task2,task3...N) Console.WriteLine("All task finished!"); }
即當task,task2,task3…N全部任務都執行完成之后才會往下執行代碼(打印出:“All task finished!”)
3、Task.WaitAny
這個用發同Task.WaitAll,就是等待任何一個任務完成就繼續向下執行,將上面的代碼WaitAll替換為WaitAny
{
Task.WaitAny(task,task2,task3...N) Console.WriteLine("Any task finished!"); }
即當task,task2,task3…N任意一個任務都執行完成之后就會往下執行代碼(打印出:” Any task finished!”)
4、Task.ContinueWith
就是在第一個Task完成后自動啟動下一個Task,實現Task的延續,下面我們來看下他的用法,編寫如下代碼:
static void Main(string[] args) { var task1 = new Task(() => { Console.WriteLine("Task 1 Begin"); System.Threading.Thread.Sleep(2000); Console.WriteLine("Task 1 Finish"); }); var task2 = new Task(() => { Console.WriteLine("Task 2 Begin"); System.Threading.Thread.Sleep(3000); Console.WriteLine("Task 2 Finish"); }); task1.Start(); task2.Start(); var result = task1.ContinueWith<string>(task => { Console.WriteLine("task1 finished!"); return "This is task result!"; }); Console.WriteLine(result.Result.ToString()); Console.Read(); }
可以看到,task1完成之后,開始執行后面的內容,並且這里我們取得task的返回值。
5、Task的取消
前面說了那么多Task的用法,下面來說下Task的取消,比如我們啟動了一個task,出現異常或者用戶點擊取消等等,我們可以取消這個任務。如何取消一個Task呢,我們通過cancellation的tokens來取消一個Task。在很多Task的Body里面包含循環,我們可以在輪詢的時候判斷IsCancellationRequested屬性是否為True,如果是True的話就return或者拋出異常,拋出異常后面再說,因為還沒有說異常處理的東西。
下面在代碼中看下如何實現任務的取消,代碼如下:
var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; var task = Task.Factory.StartNew(() => { for (var i = 0; i < 1000; i++) { System.Threading.Thread.Sleep(1000); if (token.IsCancellationRequested) { Console.WriteLine("Abort mission success!"); return; } } }, token); token.Register(() => { Console.WriteLine("Canceled"); }); Console.WriteLine("Press enter to cancel task..."); Console.ReadKey(); tokenSource.Cancel();
這里開啟了一個Task,並給token注冊了一個方法,輸出一條信息,然后執行ReadKey開始等待用戶輸入,用戶點擊回車后,執行tokenSource.Cancel方法,取消任務。
注:
- 因為任務通常運行以異步方式在線程池線程上,創建並啟動任務的線程將繼續執行,一旦該任務已實例化。 在某些情況下,當調用線程的主應用程序線程,該應用程序可能會終止之前任何任務實際開始執行。 其他情況下,應用程序的邏輯可能需要調用線程繼續執行,僅當一個或多個任務執行完畢。 您可以同步調用線程的執行,以及異步任務它啟動通過調用 Wait 方法來等待要完成的一個或多個任務。 若要等待完成一項任務,可以調用其 Task.Wait 方法。 調用 Wait 方法將一直阻塞調用線程直到單一類實例都已完成執行。
參考文獻:
1.https://www.cnblogs.com/yunfeifei/p/4106318.html
2.https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.task.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
using System; using System.Threading.Tasks; using System.Threading; namespace 實現取消選項 { class Program { static void Main(string[] args) { var cts = new CancellationTokenSource(); var longTask = new Task<int>(() => TaskMethod("Task 1", 10, cts.Token), cts.Token); Console.WriteLine(longTask.Status); cts.Cancel(); Console.WriteLine(longTask.Status); Console.WriteLine("First task has been cancelled before execution"); cts = new CancellationTokenSource(); longTask = new Task<int>(() => TaskMethod("Task 2", 10, cts.Token), cts.Token); longTask.Start(); for (int i = 0; i < 5; i++) { Thread.Sleep(TimeSpan.FromSeconds(0.5)); Console.WriteLine(longTask.Status); } cts.Cancel(); for (int i = 0; i < 5; i++) { Thread.Sleep(TimeSpan.FromSeconds(0.5)); Console.WriteLine(longTask.Status); } Console.WriteLine("A task has been completed with result {0}.", longTask.Result); Console.ReadKey(); } private static int TaskMethod(string name,int seconds,CancellationToken token) { Console.WriteLine("Task {0} is running on a thread id {1},Is thread pool thread: {2}", name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread); for (int i = 0; i < seconds; i++) { Thread.Sleep(TimeSpan.FromSeconds(1)); if (token.IsCancellationRequested) { Console.WriteLine("Cancel Task {0} is running on a thread id {1},Is thread pool thread: {2}", name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread); return -1; } } return 42 * seconds; } } }