简体   繁体   English

正确处理任务取消的一般方法

[英]General approach to handle Task cancellation correctly

I'm doing a code review, and I'm concerned about this pattern, seen all across that code: 我正在进行代码审查,并且我担心这种模式,贯穿所有代码:

try
{
    await DoSomethingAsync();
    await DoSomethingElseAsync();
    // and so on...
}
catch (OperationCanceledException)
{
    // all good, user cancelled
    // log and return
    return;
}
// handle other particular exceptions
// ...
catch (Exception ex)
{
    // fatal error, alert the user
    FatalErrorMessage(ex);
}

The part I'm concerned about is handling OperationCanceledException . 我关心的部分是处理OperationCanceledException Shouldn't this code be also handling AggregateException and checking if the only inner exception is OperationCanceledException ? 这段代码不应该也处理AggregateException并检查唯一的内部异常是否是OperationCanceledException

I know Task.Wait or Task.Result would throw an AggregateException like that, rather than OperationCanceledException . 我知道Task.WaitTask.Result会抛出类似的AggregateException ,而不是OperationCanceledException The author of the code assured me she only uses async/await inside out and never uses Wait/Result . 代码的作者向我保证她只使用async/await out out并且从不使用Wait/Result Thus, she doesn't like the idea of additionally observing AggregateException for cancellation. 因此,她不喜欢另外观察AggregateException进行取消的想法。 However, my point is some standard Task -based BCL APIs could still be wrapping OperationCanceledException with AggregateException , eg because they still might be accessing Task.Result internally. 但是,我的观点是一些标准的基于Task的BCL API仍然可以使用AggregateException包装OperationCanceledException ,例如因为它们仍然可能在内部访问Task.Result

Does it make sense? 是否有意义? Should we be worrying about handling both OperationCanceledException and AggregateException to observe cancellation correctly? 我们是否应该担心处理OperationCanceledExceptionAggregateException以正确观察取消?

However, my point is some standard Task-based BCL APIs could still be wrapping OperationCanceledException with AggregateException, eg because they still might be accessing Task.Result internally. 但是,我的观点是一些标准的基于任务的BCL API仍然可以使用AggregateException包装OperationCanceledException,例如因为它们仍然可能在内部访问Task.Result。

No, they won't do that. 不,他们不会这样做。

Should we be worrying about handling both OperationCanceledException and AggregateException to observe cancellation correctly? 我们应该担心同时处理OperationCanceledException和AggregateException以正确观察取消吗?

I would say no. 我会说不。 It is, of course, possible that an AggregateException can contain an OperationCanceledException , but it can also contain other particular exceptions just as easily. 这是当然, 可能是一个AggregateException可以包含OperationCanceledException ,但它也可以包含other particular exceptions一样容易。

As long as you follow async best practices (ie, no async-over-sync or sync-over-async), then you don't have to worry about this. 只要您遵循异步最佳实践(即,没有异步同步或同步异步),您就不必担心这一点。

Well, it's definitely technically possible which is very easy to verify with this code: 嗯,这绝对是技术上可行的,这个代码很容易验证:

static void Main()
{
    Test().Wait();
}

static async Task Test()
{
    try
    {
        await ThrowAggregate();
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
    }
}

static async Task ThrowAggregate()
{
    ThrowException().Wait();
}

static async Task ThrowException()
{
    throw new OperationCanceledException();
}

ThrowAggregate stores the AggregateException inside the returned task so awaiting it still throws AggregateException . ThrowAggregate将AggregateException存储在返回的任务内,因此等待它仍会引发AggregateException So if you want to be diligent you would need to catch AggregateException too. 因此,如果您想勤奋工作,那么也需要捕获AggregateException

However, it's very unlikely that any method in the BCL would do that and if it did you have bigger issues than exception handling since your doing async over sync. 但是,BCL中的任何方法都不太可能这样做,如果它确实存在比异常处理更大的问题,因为您执行异步过度同步。 I would be more worried about your own code. 我会更担心你自己的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM