程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> async和await關鍵字

async和await關鍵字

編輯:C#入門知識

C# 5.0中引入了async 和 await。這兩個關鍵字可以讓你更方便的按照同步的方式寫出異步代碼。也就是說使你更方便的異步編程。常規的寫法格式如下: var result = await expression;  statement(s);  這種寫法相當於:  var awaiter = expression.GetAwaiter();  awaiter.OnCompleted (() =>  {  var result = awaiter.GetResult();  statement(s);  );  這裡的expression通常是Task或者Task<TResult>,但是事實上可以自己定義一些可以使用await的對象。但是要滿足一定的條件。先看一個例子。  static void Main(string[] args)         {             DisplayPrimesCount();             Thread.Sleep(5000);//等待異步執行完成         }         static Task<int> GetPrimesCountAsync(int start, int count)         {             return Task.Run(() =>             ParallelEnumerable.Range(start, count).Count(n =>             Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0)));         }         static async void DisplayPrimesCount()         {             int result = await GetPrimesCountAsync(2, 1000000);//此處會阻塞             Console.WriteLine(result);         }  這是比較常見的寫法。 要異步執行GetPrimesCountAsync方法,首先GetPrimesCountAsync返回的必須是"可等待"對象。上述代碼中GetPrimesCountAsync返回的是Task<int>類型。然後,使用await的方法必須要標注async關鍵字。並且可以看到await GetPrimesCountAsync(2, 1000000);這個語句返回的是int,而不是Task<int>。 上述代碼用自然語言描述就是如下: 當調用DisplayPrimesCount,DisplayPrimesCount會運行一個新的Task,這個task會計算素數的個數。完成後,會將計算所得的值返回,並將這個返回值放到Task對象中,並且返回給調用者。調用者獲得這個Task值後,取出Task的result值。 當程序邏輯遇到await GetPrimesCountAsync方法,線程就會被掛起,直到異步運行完成,得到result值後,再會繼續運行下去。 本質上說await和async的出現也只是一顆語法糖,但是這顆語法糖可以使得異步編程更優雅,直接摒棄了原先EAP和APM這種到處BeginXXX,EndXXX的丑陋模式,提高了生產力。 可以使用await的方法,返回值必須是awaitable對象,自定義awaitable對象比較麻煩,一個對象必須滿足下列條件才行: 必須有一個 GetAwaiter()方法,擴展方法或者實例方法都可以 GetAwaiter() 方法返回值必須是awaiter對象。一個對象要成為awaiter對象必須滿足下列條件: 該對象實現接口 INotifyCompletion 或者ICriticalNotifyCompletion 必須有 IsCompleted屬性 必須有 GetResult()方法,可以返回void或者其他返回值。 由於微軟並未給出滿足上述條件的接口,因此可以自己實現這樣的接口。  public interface IAwaitable<out TResult>      {          IAwaiter<TResult> GetAwaiter();      }      public interface IAwaiter<out TResult> : INotifyCompletion // or ICriticalNotifyCompletion      {          bool IsCompleted { get; }          TResult GetResult();      }  由於對於拉姆達表達式不可以直接使用await,因此可以通過編程,技巧性的實現這一功能。比如對某一個Func委托實現擴展方法,注意: 擴展方法必須在頂級靜態類中定義。  public static class FuncExtensions      {          public static IAwaiter<TResult> GetAwaiter<TResult>(this Func<TResult> function)          {              return new FuncAwaiter<TResult>(function);          }      }      public interface IAwaitable<out TResult>      {          IAwaiter<TResult> GetAwaiter();      }      public interface IAwaiter<out TResult> : INotifyCompletion // or ICriticalNotifyCompletion      {          bool IsCompleted { get; }          TResult GetResult();      }      internal struct FuncAwaitable<TResult> : IAwaitable<TResult>      {          private readonly Func<TResult> function;          public FuncAwaitable(Func<TResult> function)          {              this.function = function;          }          public IAwaiter<TResult> GetAwaiter()          {              return new FuncAwaiter<TResult>(this.function);          }      }      public struct FuncAwaiter<TResult> : IAwaiter<TResult>      {          private readonly Task<TResult> task;          public FuncAwaiter(Func<TResult> function)          {              this.task = new Task<TResult>(function);              this.task.Start();          }          bool IAwaiter<TResult>.IsCompleted          {              get              {                  return this.task.IsCompleted;              }          }          TResult IAwaiter<TResult>.GetResult()          {              return this.task.Result;          }          void INotifyCompletion.OnCompleted(Action continuation)          {              new Task(continuation).Start();          }      }        在main中可以如下寫:      static void Main(string[] args)          {              Func(() => { Console.WriteLine("await..");return 0;});              Thread.Sleep(5000);//等待異步執行完成          }          static async void Func(Func<int> f)          {              int result = await new Func<int>(f);              Console.WriteLine(result);          }  其中: Func方法可以異步執行了,因為Func<int>已經實現擴展方法GetAwaiter,並且返回值類型是自己定義的IAwaitable類型。 當然,更加簡單的方法是,采用微軟提供的Task對象,讓拉姆達表達式返回Task類型就可以了。  static void Main(string[] args)          {              Func(() =>              {                  return Task<int>.Run<int>(() => { return Enumerable.Range(1,100).Sum(); });              });              Thread.Sleep(5000);//等待異步執行完成          }          static async void Func(Func<Task<int>> f)          {              int result = await f();              Console.WriteLine(result);          }  ---------------------------------

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved