2015-09-01 47 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