【问题标题】:async await exception catching - which thread am I on?异步等待异常捕获 - 我在哪个线程上?
【发布时间】:2015-09-27 01:38:59
【问题描述】:

我想做这样的事情:

public async Task<int> DoWork(int parameter) {
    try {
        await OperationThatMayCompleteSynchronously(parameter);
    } catch(Exception) e { 
        if(completedSynchronously)
           doSyncThing();
        else
           doAsyncThing();
    }
}

注意:我在线程池上运行任务,所以没有异步上下文。

我希望能够区分立即抛出的异常和我仍在调用线程上(例如 parameter 无效导致函数中止)和异步时抛出的异常任务完成,我在其他一些随机回调线程上(例如网络故障)

如果我不使用await,并且只是在异步操作中使用ContinueWith,我可以计算出如何实现这一点,但是可以使用await吗?

【问题讨论】:

  • 请记住,如果OperationThatMayCompleteSynchronously是异步方法,所有异常都会存储在任务中,不会同步抛出异常

标签: c# exception-handling async-await


【解决方案1】:

将任务存储在变量中:

var task = OperationThatMayCompleteSynchronously(parameter); //may throw

然后等待它:

await task; //may throw

这样您就可以区分潜在异常的两个来源。

注意,async 方法永远不会直接抛出。它们通过返回的任务传递异常。即使对于在第一次等待之前执行的“验证”抛出也是如此。

【讨论】:

  • @OrionEdwards,要获得您想要的 100% 行为,您需要修改上述内容以添加如下内容:var task = OperationThatMayCompleteSynchronously(parameter); if (task.IsFaulted) task.GetAwaiter().GetResult(); ...。检查this
  • @Noseratio 你能解释一下那会完成什么吗?似乎 await 就是这样做的。
  • AFAIU,如果OperationThatMayCompleteSynchronously 从其同步部分而不是await 行抛出,则OP希望第一行立即抛出。如果此方法是 async,则不会发生这种情况,例如async Task OperationThatMayCompleteSynchronously() { throw new Exception(); }。它仍然会抛出await 行,@usr。
  • @usr:考虑修改您的答案以同时更新OperationThatMayCompleteSynchronously,以便它以非异步方法执行其同步异常。否则,您的第一行实际上不会抛出。我认为这比使用IsFaulted/IsCompleted 更干净。
  • @usr:同意将线程标识作为红鲱鱼。我只想明确指出“包装器方法”,因为有时人们确实假设throw 之前await 将被直接抛出而不是放在任务上。事实上,第一个 Async CTP 确实有这种行为。
【解决方案2】:

您可以调用Wait()Result 而不是等待,因为您声称没有同步上下文,并且如果捕获的异常是AggregateException,则它不会在调用线程中抛出。

【讨论】:

    猜你喜欢
    • 2020-07-08
    • 2014-12-01
    • 2017-08-08
    • 1970-01-01
    • 2013-06-07
    • 2017-03-23
    • 2013-02-15
    • 1970-01-01
    相关资源
    最近更新 更多