我有多个任务,接受取消令牌并相应地调用 ThrowIfCancellationRequested
。这些任务将使用 Task.WhenAll
同时运行。当任何任务抛出异常时,我希望所有任务都被取消。我使用 Select
和 ContinueWith
实现了这一点:
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
。
另外,我尝试将取消标记传递给ContinueWith
,例如:task.ContinueWith(lambda, cts.Token)
。但是,当任何任务中发生异常时,这将最终引发一个TaskCanceledException
而不是我感兴趣的异常。我认为应该将取消标记传递给ContinueWith
,因为这将取消ContinueWith
本身,而我认为这不是我想要的。
WhenAll
只是使用ContinueWith
添加自己的继续,当它确定是否应该故障它自身时,它将检查Exception
值,留下了完全相同的问题。其中一些发生在WhenAll
的后台并没有实质性的区别,解释或纠正问题都是一样的。 - ServyWhenAll
隐含地附加了它自己的连续操作,另一个线程并未涉及此主题。因此,我不认为我的问题是重复的。 - Rudeyasync
/await
,直到现在我从未使用过ContinueWith
。只有因为你最后的评论,我才明白将一个继续添加到一个失败的任务会导致一个不会失败的任务。 - Rudey