1. 程式人生 > 實用技巧 >基於任務的非同步程式設計(Task,async,await)

基於任務的非同步程式設計(Task,async,await)

這節講一下比較高階的非同步程式設計用法Task,以及兩個非同步關鍵字async和await。

Task是在C#5.0推出的語法,它是基於任務的非同步程式設計語法,是對Thread的升級,也提供了很多API,先看一下Task怎麼使用:

System.Threading.Tasks.Task.Run(() =>
  {
      Console.WriteLine("非同步");
  });
  System.Threading.Tasks.Task aTask=new System.Threading.Tasks.Task(() =>
  {
      Console.WriteLine(
"非同步"); }); aTask.Start(); System.Threading.Tasks.Task.Factory.StartNew(() => { Console.WriteLine("非同步"); });

Task.Run()可以直接非同步執行一個方法,或者使用例項化Task傳入委託的方式,通過start()進行啟動,再或者使用Task.Factory.StartNew()直接啟動。

async,await

為了進一步介紹Task,需要先介紹兩個非同步有關的關鍵字async,await

async用在方法的宣告,await用於程式碼語句中。被async標記的方法,稱作非同步方法。但是,並非整個方法都是非同步執行,程式碼中以await開頭標記的程式碼,才是要真正非同步執行的具體內容。這個關鍵字一般是配合Task來使用的,Task有泛型的形式,標識非同步的返回值型別,通過Result()方法獲取返回值。這段說明很難理解,下面看程式碼演示:

static void Main(string[] args)
{
    Console.WriteLine("新建一個非同步任務");
    Task<int> task = new Program().GetValue();
​
    Console.WriteLine("正在計算結果....");
    Console.WriteLine($"執行結果為:{task.Result}");
    Console.WriteLine("任務完成....");
}
public async Task<int> GetValue()
{
    Console.WriteLine(
"即將開始進行計算...3"); Console.WriteLine("即將開始進行計算...2"); Console.WriteLine("即將開始進行計算...1"); int a= await System.Threading.Tasks.Task.Run(() => { int i = 0; for (; i < 10; i++) { Console.WriteLine(i); } return i; }); Console.WriteLine("結果計算完成...."); return a; }

執行結果為:

從執行結果可以看出,程式執行到15行await處後,下一步就跳出了這個方法,回到第6行執行,這也是await的一個特性,非同步執行,將主執行緒執行權交回,也就是說,從15行到25行是在後臺執行緒中執行的,之前的執行都是同步的,之後的執行也是同步的,而且,主執行緒的腳步沒有停下,直到遇到task.Result,Result裡邊存放著非同步方法執行的返回值,執行到這,如果非同步沒有完成,就會阻塞當前執行緒,直到非同步返回結果。

另外說一點,之前在講自定義中介軟體的時候,涉及到過這兩個關鍵詞,現在明白了這個用法,可以回去再看一下,應該會對中介軟體的訪問流程有一個更清晰的理解。

ContinueWith

ContinueWith設定Task在執行完原有任務後,再繼續執行此方法設定的方法,下面看程式碼:

task.ContinueWith((task) =>
  {
      Console.WriteLine("---------------"+a.Result);
  });

這是其中的一個過載,接受一個Action<Task<T>>型別的委託,此處乍一看可能會不解,其實就是把當前執行任務的Task物件傳進來了。這樣的用法有什麼好處呢,執行完了以後,可以直接取Task任務的返回值,不用阻塞執行緒,當然這是在返回值不是急需的情況下。

CancellationTokenSource

CancellationTokenSource類用於終止一個任務,請先看一下程式碼:

static void Main(string[] args)
{
    CancellationTokenSource cancellationToken=new CancellationTokenSource();
​
    Task<int> task= new Program().GetValue(cancellationToken);
    cancellationToken.Cancel();
    Console.WriteLine("正在計算結果....");
​
    Console.WriteLine($"執行結果為:{task.Result}");
    Thread.Sleep(1000);
    Console.WriteLine("任務完成....");
}
public Task<int> GetValue(CancellationTokenSource cancellationToken)
{
    Task<int> a = System.Threading.Tasks.Task.Run(() =>
     {
         int i = 0;
         for (; i < 100; i++)
         {
             Console.WriteLine(i);
             Thread.Sleep(500);
         }
         return i;
     },cancellationToken.Token);
    Console.WriteLine("結果計算完成....");
    return a;
}

建立一個CancellationTokenSource物件,在Run任務的時候傳入一個Token,就能呼叫Cancel()方法就能終止這個任務,執行結果為:

可以看到報錯了,這很正常,因為任務停止了,顯然Result是沒有值的

最後注意一點,非同步不是多執行緒,可以說非同步是基於多執行緒,但是它們不是等於的關係。

這是我的公眾號二維碼,獲取最新文章,請關注此號