我有多個任務接受取消令牌並相應地調用ThrowIfCancellationRequested
。這些任務將使用Task.WhenAll
同時運行。當任何任務拋出異常時,我希望取消所有任務。我實現了這個使用Select
和ContinueWith
:如何正確取消Task.WhenAll並拋出第一個異常?
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
本身,我不認爲這是我想要的是。
@Servy這個問題與「複製」之間的區別,這是關於'Task.WhenAll '並在任務外使用try-catch。另一個問題是關於連接多個'ContinueWith'並顯式檢查task.Exception。 –
區別是不相關的。 'WhenAll'只是使用'ContinueWIth'附加它自己的延續,並且在確定是否應該自己排除故障時會檢查'Exception'的值,從而給你帶來完全相同的問題。 「WhenAll」幕後發生的一些情況與解釋問題或糾正問題沒有多大區別。 – Servy
@Servy我不明白你的解釋或其他線程如何回答我的問題,如何讓異常像通常那樣被拋出,從而允許我在另一層調用堆棧上處理TPL之外的異常。 –