gpt4 book ai didi

c# - 如何正确取消 Task.WhenAll 并抛出第一个异常?

转载 作者:太空狗 更新时间:2023-10-30 00:09:57 41 4
gpt4 key购买 nike

我有多个任务接受取消 token 并相应地调用 ThrowIfCancellationRequested。这些任务将使用 Task.WhenAll 同时运行。我希望在任何任务抛出异常时取消所有任务。我使用 SelectContinueWith 实现了这一点:

var cts = new CancellationTokenSource();

try
{
var tasks = new Task[] { DoSomethingAsync(cts.Token), ... } // multiple tasks here
.Select(task => task.ContinueWith(task =>
{
if (task.IsFaulted)
{
cts.Cancel();
}
}));

await Task.WhenAll(tasks).ConfigureAwait(false);
}
catch (SpecificException)
{
// Why is this block never reached?
}

我不确定这是否是最好的方法,它似乎有一些问题。看起来异常将在内部被捕获,总是到达 WhenAll 之后的代码。我不希望在发生异常时到达 WhenAll 之后的代码,我宁愿抛出异常,这样我就可以在调用堆栈的另一层手动捕获它。实现这一目标的最佳方法是什么?如果可能的话,我希望调用堆栈保持不变。如果发生多个异常,最好只重新抛出第一个异常,而不是 AggregateException


在相关说明中,我尝试将取消 token 传递给 ContinueWith,如下所示:task.ContinueWith(lambda, cts.Token)。但是,当任何任务发生异常时,这最终将抛出 TaskCanceledException 而不是我感兴趣的异常。我想我应该将取消 token 传递给 ContinueWith因为这会取消 ContinueWith 本身,我认为这不是我想要的。

最佳答案

你不应该使用 ContinueWith。正确的答案是引入另一个“更高级别的”async 方法,而不是为每个任务附加一个延续:

private async Task DoSomethingWithCancel(CancellationTokenSource cts)
{
try
{
await DoSomethingAsync(cts.Token).ConfigureAwait(false);
}
catch
{
cts.Cancel();
throw;
}
}


var cts = new CancellationTokenSource();
try
{
var tasks = new Task[] { DoSomethingWithCancel(cts), ... };
await Task.WhenAll(tasks).ConfigureAwait(false);
}
catch (SpecificException)
{
...
}

关于c# - 如何正确取消 Task.WhenAll 并抛出第一个异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42378265/

41 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com