基於任務的異步編程模式(TAP) 基於任務的異步編程模式(TAP)的錯誤處理

異步編程是C#5.0的一個重要改進,提供兩個關鍵字:async和await。使用異步編程,方法的調用是在後臺運行(一般在線程或任務的幫助下),但不會阻塞調用線程。異步模式分爲3種:異步模式、基於事件的異步模式和基於任務的異步模式(TAP)。TAP是利用關鍵字async和await實現的,本文將講解TAP模式。async和await關鍵字只是編譯器的功能。編譯器最終會用Task類建立代碼。html

一、建立任務

創建一個同步方法Greeting,該方法在等待一段時間後,返回一個字符串。編程

 private string Greeting(int delay, string name)
 {
     System.Threading.Thread.Sleep(delay);
     return string.Format("Hello, {0}.", name);
 }

定義一個方法GreetingAsync,能夠使方法異步化,其傳入的參數不作強制要求。基於任務的異步模式指定,並返回一個任務。注意,該方法返回的是Task<string>,定義了一個返回字符串的任務,與同步方法返回值一致。數組

private Task<string> GreetingAsync(string name, int delay = 3000)
{
    return Task.Run<string>(() =>
    {
        return Greeting(delay, name);
    });
}

二、調用異步方法

能夠使用await關鍵字調用返回任務的異步方法GreetingAsync。可是,使用await關鍵字的方法必需要用async關鍵字修飾符聲明。在GreetingAsync方法完成前,被async關鍵字修飾的方法內await關鍵字後面的代碼不會繼續執行。可是,啓動被async關鍵字修飾的方法的線程能夠被重用,而沒有被阻塞。異步

public async void CallerWithAsync()
{
    string result = await GreetingAsync("Nigel", 2000);
    Console.WriteLine(result);
}

 注意:async修飾符修飾只能用於返回Task或void的方法。不能做爲程序的入口點,即Main方法不能使用async修飾符。await修飾符只能用於返回Task的方法。

三、延續任務

GreetingAsync方法返回一個Task<string>對象。該對象包含任務建立的信息,並保存到任務完成。Task類的ContinueWith方法可在任務完成後繼續調用的代碼。async

 public void CallsWithContinuationTask()
 {
     Task<string> task = GreetingAsync("Stephanie", 1000);
     task.ContinueWith(t =>
     {
         Console.WriteLine(t.Result);
     });
 }

實際上,編譯器會把await關鍵字後的全部代碼放進ContinueWith方法內。不管是await關鍵字的方法仍是任務的ContinueWith方法,在方法的不一樣生命階段使用了不一樣的線程。都是當await關鍵字的方法或任務執行完畢後,再由另外一個線程去執行await關鍵字後面的代碼,或給當前線程添加新的任務去執行相關代碼。異步編程

在具備UI的應用程序中,應用程序的窗體的控件不容許跨線程訪問,須要使用控件的InvokeRequired屬性和Invoke方法,將訪問UI的方法代碼塊以委託的形式傳遞給控件的Invoke,可是在執行前須要判斷控件的InvokeRequired。在使用async和await關鍵字,當await完成後,不須要作任何處理,就能夠放訪問UI線程(其實是將控制權又交給了UI線程)。post

四、使用多個異步方法

4.一、按順序調用多個異步方法

使用await關鍵字能夠調用每一個異步方法。若是一個異步方法依賴於另外一個異步方法,將會起到很大做用。但當異步方法之間沒有相互依賴的時候,不使用await關鍵字將更快返回結果。ui

 public async void MultipleAsyncMethods()
 {
     DateTime start = DateTime.Now;
     string result1 = await GreetingAsync("Jack",2500);//先執行完它
     string result2 = await GreetingAsync("Tim",1500);//再執行它
     //輸出結果
     Console.WriteLine("Finished both methods: MultipleAsyncMethods.\nResult 1: {0}, Result 2: {1}", result1, result2);
     Console.WriteLine("Use time: {0}", (DateTime.Now - start).TotalMilliseconds);
 }

4.二、使用組合器

若是任務之間並不依賴於另外一個任務,每一個異步方法都不須要使用await,而是把每一個異步方法的返回結果賦值給Task變量,使用組合器讓這些任務並行運行。當組合器內的全部任務都完成後,纔會執行後面的代碼。url

public async void MultipleAsyncMethodsWithCombinators1()
{
    DateTime start = DateTime.Now;
    Task<string> t1=  GreetingAsync("Jack", 2500);
    Task<string> t2= GreetingAsync("Tim", 1500);
    await Task.WhenAll(t1, t2);
    //輸出結果
    Console.WriteLine("Finished both methods: MultipleAsyncMethodsWithCombinators1.\nResult 1: {0}, Result 2: {1}", t1.Result, t2.Result);
    Console.WriteLine("Use time: {0}", (DateTime.Now - start).TotalMilliseconds);
}

若是全部任務類型都返回相同的類型,則可用該類型的數組做爲await返回的結果spa

public async void MultipleAsyncMethodsWithCombinators2()
{
    DateTime start = DateTime.Now;
    Task<string> t1 = GreetingAsync("Jack", 2500);
    Task<string> t2 = GreetingAsync("Tim", 1500);
    string[] results= await Task.WhenAll(t1, t2);
    //輸出結果
    Console.WriteLine("Finished both methods: MultipleAsyncMethodsWithCombinators2.\nResult 1: {0}, Result 2: {1}", results[0], results[1]);
    Console.WriteLine("Use time: {0}", (DateTime.Now - start).TotalMilliseconds);
}

 五、異步方法的異常處理

若是調用異步方法,可是沒有等待,那麼調用異步方法的線程中使用傳統的try/catch塊是不能捕獲到異步方法中的異常。由於在異步方法執行出現異常以前,已經執行完畢。

如何捕獲異常見《基於任務的異步編程模式(TAP)的錯誤處理》。

相關文章
相關標籤/搜索