当等待的async
方法抛出异常时,该异常存储在某个地方并抛出它被延迟。在WinForms或WPF应用程序中,它使用SynchronizationContext.Current
来引发抛出异常。但是,例如,一个控制台应用程序,它会在线程池中引发异常,并使应用程序停止运行。从异步中捕获未处理的异常
如何防止从async
方法抛出的异常将应用程序关闭?
编辑:
Appearantly我所描述的问题是因为我有void
async
方法。看评论。
当等待的async
方法抛出异常时,该异常存储在某个地方并抛出它被延迟。在WinForms或WPF应用程序中,它使用SynchronizationContext.Current
来引发抛出异常。但是,例如,一个控制台应用程序,它会在线程池中引发异常,并使应用程序停止运行。从异步中捕获未处理的异常
如何防止从async
方法抛出的异常将应用程序关闭?
编辑:
Appearantly我所描述的问题是因为我有void
async
方法。看评论。
当async
方法启动时,它捕获当前的同步上下文。解决此问题的一种方法是创建您自己的同步上下文来捕获异常。
的这里的一点是,同步上下文的帖子回调线程池,但它周围的try/catch语句:
public class AsyncSynchronizationContext : SynchronizationContext
{
public override void Send(SendOrPostCallback d, object state)
{
try
{
d(state);
}
catch (Exception ex)
{
// Put your exception handling logic here.
Console.WriteLine(ex.Message);
}
}
public override void Post(SendOrPostCallback d, object state)
{
try
{
d(state);
}
catch (Exception ex)
{
// Put your exception handling logic here.
Console.WriteLine(ex.Message);
}
}
}
在catch
上面你可以把你的异常处理逻辑。
接下来,每一个线程(SynchronizationContext.Current
是[ThreadStatic]
)要执行async
方法用这种机制,则必须设置当前同步上下文:
SynchronizationContext.SetSynchronizationContext(new AsyncSynchronizationContext());
完整Main
例如:
class Program
{
static void Main(string[] args)
{
SynchronizationContext.SetSynchronizationContext(new AsyncSynchronizationContext());
ExecuteAsyncMethod();
Console.ReadKey();
}
private static async void ExecuteAsyncMethod()
{
await AsyncMethod();
}
private static async Task AsyncMethod()
{
throw new Exception("Exception from async");
}
}
我很抱歉,但是我没有看到你的SynchronizationContext在线程池中发布了什么,只要我能看到它所做的就是立即在调用线程上执行函数并返回。 –
如何防止从异步方法抛出的异常关闭应用程序?
遵循以下最佳实践:
async
方法应该返回Task
或Task<T>
,除非他们有返回void
(例如,事件处理程序)。async
方法await
所有Task
s返回。如果您不再关心操作的结果(例如,在取消操作后),您不希望这样做的唯一原因。async void
事件处理程序中捕获一个异常,然后在事件处理程序中捕获它 - 完全像你会这样做,如果这是同步代码。您可能会发现我的async
/await
intro post有帮助;我还介绍了其他几个最佳实践。
我知道我得到的问题是我有'无效''async'方法。但是,这是否意味着我所描述的问题确实发生在事件处理程序上? –
是的;重申第三点,如果你有一个'async void'事件处理程序,你可能想要在*那个事件处理程序中捕获异常*。同步事件处理程序会有完全相同的问题 - 如果异常在线程池线程上运行时发生异常,它会使应用程序崩溃。 –
除了异常被路由到'async'方法被调用时捕获的'SynchronizationContext'。在WinForms/WPF应用程序中,大多数时候这将是一个正确的同步上下文,因为事件很可能是从UI线程启动的。看起来行为与事件不是“异步”时发生的行为没有什么不同。 –
如果等待异步方法,则在等待它的代码中引发异常。只有当方法返回“void”时,未处理的异常才会这样。这是尽可能避免使用“异步无效”方法的原因。 – svick
@svick'async void'方法导致确定性行为;调用一个导致出现异常并且不等待任务的“任务”返回函数将会在垃圾收集器运行时在将来的某个半任意点引发'UnobservedTaskException'事件,如果这种情况什么都不做,那么让程序静静地继续如果一切都好的话。问题不在于'async void'方法,它们只是暴露了真正的问题。如果您不*从'async'方法调用'Task'返回函数,那么您很可能会做错某些事情。 – hvd
顺便说一下,只有“很好的机会”,因为有一些例外情况(无双关语意图)的情况下,可以丢弃例外,但不是很多。 – hvd