c# 異步編程

1. 引入web

  同步,任務以固定的順序執行。異步,任務不須要按照固定順序執行。從.net4.5開始,異步主要經過Task實現。異步編程的核心是Task和Task<T>對象,用來模擬異步操做,並經過async和await關鍵字修飾。其中異步模型的操做,通常分爲如下2種:數據庫

  (1)對於I/O綁定的代碼,await將在異步方法中返回一個Task或Task<T>;編程

  (2)對於綁定CPU類的程序,await將在帶有Task.Run()方法的後臺線程上啓動操做;緩存

2. 異步編程的三種模式異步

  • 基於任務的異步模式(TAP):TAP在.NET4.0中引入,使用單個犯法來表示異步操做的啓動和完成,.NET中推薦使用該方法實現異步編程。 
  • 基於事件的異步模式(EAP):EAP在.NET Framework2.0中引入,用於提供異步行爲的基於事件的遺留模型,須要一個async後綴的一個或多個時間,時間處理程序委託Type和EventArg-derived類型的方法。
  • 異步編程模型(APM):APM模型也稱爲AsyncResult模式,是使用IAsyncResult接口提供異步行爲的傳統模型。該模式中,異步操做須要begin()和end()方法,目前不推薦開發中使用該方法。

  這三種模式的實現,以"從指定的偏移量開始將指定數量的數據讀入提供的緩存區"爲例進行實現。async

   public class MyClass
    {
        public int Read(byte[] buffer, int offset, int count);
    }

  該方法的TAP模式實現以下:異步編程

    public class MyClass
    {
       public Task<int> ReadAsync(byte[] buffer, int offset, int count);
    }

  EAP對應方法將公開一下類型和成員:測試

public class MyClass  
{  
    public void ReadAsync(byte [] buffer, int offset, int count);  
    public event ReadCompletedEventHandler ReadCompleted;  
}  

  APM模式下實現以下:spa

public class MyClass  
{  
    public IAsyncResult BeginRead(byte [] buffer,int offset, int count,AsyncCallback callback, object state);  
    public int EndRead(IAsyncResult asyncResult);  
}  

3. 異步操做的實現.net

3.1 I/O綁定實例  

  場景描述: 點擊按鈕從web服務下載數據,但不能鎖定UI線程。

private readonly HttpClient _httpClient=new HttpClient();
downloadButton.Click +=async (o,e)=>
{
       //在web服務請求發生時間向UI提供控制
       //UI線程自由地執行其餘工做
       var stringData = await _httpClient.GetStringAsync(URL);
       DoSomethingWithData(stringData);
 }

3.2 CPU綁定實例:執行遊戲計算

  場景描述:寫一個手機端遊戲,點擊按鈕對屏幕上許多敵人形成傷害,但執行損害計算的代價多是昂貴的,而且在UI線程上執行計算時可能致使界面暫停。

  解決該問題的最佳辦法是開啓一個用Task.Run工做的後臺線程,用await等待返回結果。

private DamageResult CalculateDamageDone()
{
    // Code omitted:
    //
    // Does an expensive calculation and returns
    // the result of that calculation.
}

calculateButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI while CalculateDamageDone()
    // performs its work.  The UI thread is free to perform other work.
    var damageResult = await Task.Run(() => CalculateDamageDone());
    DisplayDamage(damageResult);
};

3.3 關鍵點

  • 異步操做既可用於I/O綁定代碼,也可用於CPU綁定代碼;
  • 異步代碼使用Task<T>和task,task用於在後臺工做模式的構造;
  • async關鍵字標記方法爲異步方法,容許在方法體中使用await關鍵字;
  • 當使用await關鍵字時,會暫停調用方法,並將控制權返回給它的調用方,知道等待的任務完成;
  • await只能被應用在async修飾的方法內

3.4 如何分辨是I/O綁定仍是CPU綁定?

  (1)若是代碼須要「等待」,例如來自數據庫的數據,則爲I/O綁定;

  (2)若是代碼執行須要消耗大代價的計算,則爲CPU綁定。  

4. 總結

  • async void只用於事件處理程序;async void方法中拋出的異常不能在該方法以外捕獲;async void方法很難測試;async void若是調用者不但願是異步的,方法可能會有錯誤。
  • LINQ中的lambda表達式延遲執行,若是書寫錯誤,可能很容易引發死鎖。
相關文章
相關標籤/搜索