[英]Handling multiple exceptions from async parallel tasks
問題
有幾個任務是並行運行的,all,none或者其中任何一個都可能拋出異常。 當所有任務完成后,必須報告所有可能發生的異常(通過日志,電子郵件,控制台輸出......等等)。
預期的行為
我可以使用Task.WhenAll(tasks)
lambdas通過linq構建所有任務,然后等待它們與Task.WhenAll(tasks)
並行運行。 然后我可以捕獲AggregateException
並報告每個單獨的內部異常。
實際行為
拋出了AggregateException
,但它只包含一個內部異常,無論拋出多少個別異常。
最小的完整可驗證的例子
static void Main(string[] args)
{
try
{
ThrowSeveralExceptionsAsync(5).Wait();
}
catch (AggregateException ex)
{
ex.Handle(innerEx =>
{
Console.WriteLine($"\"{innerEx.Message}\" was thrown");
return true;
});
}
Console.ReadLine();
}
private static async Task ThrowSeveralExceptionsAsync(int nExceptions)
{
var tasks = Enumerable.Range(0, nExceptions)
.Select(async n =>
{
await ThrowAsync(new Exception($"Exception #{n}"));
});
await Task.WhenAll(tasks);
}
private static async Task ThrowAsync(Exception ex)
{
await Task.Run(() => {
Console.WriteLine($"I am going to throw \"{ex.Message}\"");
throw ex;
});
}
產量
請注意,由於競爭條件,“我要投擲”消息的輸出順序可能會發生變化。
I am going to throw "Exception #0"
I am going to throw "Exception #1"
I am going to throw "Exception #2"
I am going to throw "Exception #3"
I am going to throw "Exception #4"
"Exception #0" was thrown
這是因為await
“解包”聚合異常並且總是拋出第一個異常(如await文檔中所述),即使等待Task.WhenAll
顯然會導致多個錯誤。 您可以訪問聚合異常,例如:
var whenAll = Task.WhenAll(tasks);
try {
await whenAll;
}
catch {
// this is `AggregateException`
throw whenAll.Exception;
}
或者你可以循環遍歷任務並檢查每個任務的狀態和異常。
請注意,在修復之后,您還需要做一件事:
try {
ThrowSeveralExceptionsAsync(5).Wait();
}
catch (AggregateException ex) {
// flatten, unwrapping all inner aggregate exceptions
ex.Flatten().Handle(innerEx => {
Console.WriteLine($"\"{innerEx.Message}\" was thrown");
return true;
});
}
因為ThrowSeveralExceptionsAsync
返回的任務包含我們拋出的AggregateException
,包含在另一個AggregateException
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.