【问题标题】:is await task equal to throwing the exception of the faulted task in the ContinueWith是等待任务等于在ContinueWith中抛出故障任务的异常
【发布时间】:2013-04-22 19:53:18
【问题描述】:

以下不是多余的吗?

await blob.CopyToBlobAsync(newBlob).
       ContinueWith((t) => { if (t.IsFaulted) throw t.Exception; });

好像没有ContinueWith调用一样,直接抛出异常?

什么时候可以使用 continueWith 而不是等待任务?

下面是一样的吗?

await myTask.ContinueWith(t => {'do something with the task t'});

await myTask;
'do something with the task MyTask'

【问题讨论】:

    标签: c# async-await


    【解决方案1】:

    ContinueWith(t => { if (t.IsFaulted) throw t.Exception; }) 行与 await 直接执行 CopyToBlobAsync 任务具有不同的语义:

    • 它忽略取消结果;即使CopyToBlobAsync 返回的Task 被取消,ContinueWith 返回的Task 也会成功完成。这可能是故意行为。
    • 它忽略成功的结果; CopyToBlobAsync 的任何返回值都将被删除。
    • 它通过直接抛出t.Exception 将任何异常包装在AggregateException 中。这几乎可以肯定是错误的行为。

    所以这不是完全多余的,而且很可能是个错误。

    在某些情况下,您可以使用ContinueWith 而不是await 执行任务。在我的代码中,我通常只在延续很简单的情况下这样做,我不需要延续中的上下文,并且我不想要async 状态机的开销。在大多数情况下,您应该更喜欢 await 可能与 ConfigureAwait(false) 结合使用。

    你最后的例子不一样; ContinueWith 默认将在线程池上执行,而await 默认将捕获一个上下文并在该上下文中执行延续。此外,您必须非常小心如何在 continuation 中使用任务:您通常希望将异常和取消传播到 continuation 任务,这并不像最初看起来那么容易。

    简而言之,我几乎在所有情况下都推荐await。它更易于编写、更易于阅读,并且具有合理的默认行为。

    【讨论】:

    • 我有一种情况,我在循环中创建和启动任务,并使用信号量限制并发运行的任务数。我继续处理任务并检查它们是否失败,如果是,则将 ID 添加到 ConcurrentBag 中,这样我可以查看是否全部成功。我无法从我的 continueWith 委托中正确分配到我的 out 任务(运行循环的任务)的异常。 (这听起来很愚蠢,还是应该添加代码以进行澄清)。
    • 我建议您查看 TPL 数据流。听起来它对您的场景很有用。
    • ActionBlock 对我来说可能很有趣。是否正确理解,我可以将其定义为需要多次运行的代码,只要我有输入,只需将输入发布到它。
    • 效果不太好。 ActionBlock 执行正确,但它会一一处理发布给它的数据。我的另一个解决方案同时启动了 N 个任务。您是否希望我阅读它只是为了更好地理解 TPL 或特定内容?
    • 您可以使用MaxDegreeOfParallelism 块选项;默认设置为 1。
    猜你喜欢
    • 2018-07-07
    • 1970-01-01
    • 2014-06-28
    • 2014-09-06
    • 1970-01-01
    • 2016-01-13
    • 2014-10-30
    • 2014-03-18
    • 2020-08-05
    相关资源
    最近更新 更多