为什么Task.WhenAll抛出TaskCanceledException和Task.WhenAny不在同一个测试用例中

nel*_*eus 3 .net asynchronous async-await

我运行这段代码:

var cancellation = new CancellationTokenSource();
var cancelledTask1 = .....;//starting new long-running task that accepts cancellation.Token
var cancelledTask2 = .....;//starting new long-running task that accepts cancellation.Token

//then I request cancellation
cancellation.Cancel();
//some task gets cancelled before code below executes
try
{
    //wait for completion (some task is already in cancelled state)
    await Task.WhenAll(cancelledTask1, cancelledTask2);
}
catch (OperationCanceledException e)
{
    Logger.Debug("await WhenAll", e);
}
Run Code Online (Sandbox Code Playgroud)

我明白了

await WhenAll System.Threading.Tasks.TaskCanceledException: A task was canceled.
Run Code Online (Sandbox Code Playgroud)

我认为它很少,因为某些任务已经处于取消状态.为什么Task.WhenAll方法会破坏正常流程并在取消子任务时抛出异常?什么是受益于这种行为?

然后,我尝试了这个方法Task.WhenAny:

var cancellation = new CancellationTokenSource();
var cancelledTask3 = .....;//starting new long-running task that accepts cancellation.Token

//then I request cancellation
cancellation.Cancel();
//the task gets cancelled before code below executes
try
{
    //wait for completion (the task is already in cancelled state)
    await Task.WhenAny(cancelledTask3);
}
catch (OperationCanceledException e)
{
    Logger.Debug("await WhenAny", e);
}
Run Code Online (Sandbox Code Playgroud)

它不会抛出异常.

第二个问题是为什么Task.WhenAny不在同一案例中抛出异常?我希望这两种方法都应该以相同的方式处理被取消的任务:抛出异常与否.

Dor*_*oby 5

Task.WhenAny设计用于在其中一个任务完成时完成,其中完成包括失败.实际上,当其中一个任务失败时,我发现它最有用.例如:

try
{
   await Task.WhenAny(task1,task2);
   cancellationToken.Cancel(); //cancel all tasks
   await Task.WhenAll(task1,task2); //wait for both tasks to respect the cancellation
}
catch (Exception x)
{
...
}
Run Code Online (Sandbox Code Playgroud)

在这里,我只需要完成一项任务(因此,WhenAny).在这种情况下,我也想取消其他任务.然后我调用WhenAll等待其他任务来遵守取消请求,并且如果发生了异常,也会传播异常.

换句话说,Task.WhenAny它旨在让您在其他任务仍在运行时执行某些操作,并且它不会抛出异常以便让您使用其他任务执行任何操作.Task.WhenAll仅在所有任务完成(成功与否)时完成.它可以抛出异常,因为没有什么可以让你处理,计算完成了.