Async Console Programs 非同步控制檯程式

tkbSimplest發表於2015-09-26

如果你正在寫一個控制檯程式,你可能最終想要一個非同步的main方法,像這樣:

class Program
{
  static async void Main(string[] args)
  {
    ...
  }
}

很不幸,那個沒用(實際上,VS 11 編譯器拒絕非同步Main方法)。我的這篇部落格《Async and Await 非同步和等待》裡講過,當非同步方法完成後會返回到它的呼叫者。雖然這在UI應用(方法僅僅返回到UI事件迴圈)和ASP.NET(方法脫離執行緒返回但請求還是活著的【在生命週期內】)中執行很完美,但在控制檯程式中不會工作得這麼好:因為Main返回到作業系統,因此你的程式退出了。

你可以通過提供你自己的相容非同步上下文來變通一下。AsyncContext(非同步上下文)是通用的上下文,它用來啟用非同步的MainAsync:

class Program
{
  static int Main(string[] args)
  {
    try
    {
      return AsyncContext.Run(() => MainAsync(args));
    }
    catch (Exception ex)
    {
      Console.Error.WriteLine(ex);
      return -1;
    }
  }

  static async Task<int> MainAsync(string[] args)
  {
    ...
  }
}

以下為一個較為常見的問題,望園友們注意!

問:關於使用".Wait()"來等待一個來自非非同步的Main方法的非同步方法,推薦使用AsyncContext嗎?

答:在Main方法中要麼使用AsyncContext,要麼使用GetAwaiter().GetResult()。GetAwaiter().GetResult()本質上和Wait()一樣,但是它沒有把異常封裝在AggregateException中。

AsyncContext在主控制檯執行緒中裝配了一個真實的單執行緒上下文。GetAwaiter().GetResult()將自由上下文預設保留在控制檯應用中。如果我在寫一個概念證明型的程式碼,並且最終在ASP.NET或者UI應用(具有單執行緒上下文)中終止,我通常就會使用AsyncContext;如果我在寫一個真實的控制檯應用,我可以任選一種方式。

 


相關文章