2015-09-01 48 views
-2

我遵循Microsoft指定的模式。 https://msdn.microsoft.com/en-us/library/hh191443.aspx如何處理多個異常與異步等待

本文介紹使用await開發異步代碼。但是,他們不會談論在等待退貨之前發生異常時會發生什麼情況。

在下面的例子中,外部異常結束父線程,任務沒有線程返回。我如何處理這個scneario?

class Program 
    { 
     private static void Main(string[] args) 
     { 
      CallAsync(); 
      Console.ReadKey(); 
     } 

     public static async void CallAsync() 
     { 
      var task = CallExceptionAsync(); 
      ThrowException("Outside"); 
      await task; 
     } 

     public static Task CallExceptionAsync() 
     { 
      return Task.Run(() => 
      { 
       ThrowException("Inside"); 
      }); 

     } 

     public static void ThrowException(string msg) 
     { 
      throw new Exception(msg); 
     }   
    } 

回答

0

你必須做好準備,以處理可能已經被周圍用一個try/catch這一呼籲滲出回你的主線程異常。在這種情況下,您應該收到一個AggregateException,它包含來自異步線程的一個或多個異常。

+0

我誤解了你的例子。我說的對於你開始的第二個線程來說是正確的,但是你也在主線程級別拋出一個異常。你想說啥?如果你沒有該主線程異常的catch塊,它將被終止(或被更高一些的其他代碼捕獲)。你問第二個線程會發生什麼,如果第一個線程在它之前終止? –

+0

我的例子是一個愚蠢的例子。我的實際代碼更復雜,我能夠在這裏複製相同的行爲。 在我的原始代碼中,我正在調用Web服務,並保存到數據庫。兩者都拋出異常。我可以在這裏以一個更簡單的例子複製它。 不管它是否在主要或沒有.wait()。行爲仍然是這樣的 – Anish

+0

我會在這裏拋出另一個問題的評論:我的理解是,如果主線程終止,它的所有子線程同時終止。這是真的? –

0

這正是您不應該使用async void的原因。在常規異步方法中,從方法主體拋出的異常被捕獲並存儲在返回的任務中。由於在async void的情況下,調用者沒有任何任務來觀察異常帶來的過程。

所以,你應該返回一個任務,並在Main的情況下,你可以用Task.Wait同步塊:

private static void Main() 
{ 
    CallAsync().Wait(); 
} 

public static async Task CallAsync() 
{ 
    var task = CallExceptionAsync(); 
    ThrowException("Outside"); 
    await task; 
} 

Task.Wait阻塞是不是一個真正的應用程序適當的解決方案,因爲它可能會導致死鎖其中涉及SynchronizationContext。在這種情況下,您可以使用Stephen Cleary的AsyncContext

+0

你可以進一步瞭解AsyncContext嗎? – Anish

+0

@Anish它爲控制檯應用程序提供了一個'SynchronizationContext',它沒有任何(與UI應用程序不同)。但那不是重點。關鍵是避免「異步無效」。 'async void'只適用於事件處理程序。 – i3arnon