[英]Why is only one from many exceptions from child tasks always propagated?
我正在努力更好地掌握TPL中異常和錯誤處理的原理(以及.NET 4.5異步/等待任務中的更多運氣)
對我之前的問題“如何更好地理解“異步-處理多個異常”一文中的代碼/語句”做了些修改?” 運行2個分離的內部嵌套附加(相關)子對象的C#控制台應用程序代碼(更新:抱歉,開始一個問題,但由另一個問題結束!)任務:
class Program
{
static void Main(string[] args)
{ Tst();
Console.ReadLine();
}
async static Task Tst()
{
try
{
await Task.Factory.StartNew
(() =>
{
Task.Factory.StartNew
( () => {
Console.WriteLine("From 1st child");
throw new NullReferenceException();
}
, TaskCreationOptions.AttachedToParent
);
Task.Factory.StartNew
( () =>
{
Console.WriteLine("From 2nd child");
throw new ArgumentException();
}
,TaskCreationOptions.AttachedToParent
);
}
);
}
catch (AggregateException ex)
{
Console.WriteLine("** {0} **", ex.GetType().Name);
foreach (var exc in ex.Flatten().InnerExceptions)
{
Console.WriteLine(exc.GetType().Name);
}
}
catch (Exception ex)
{
Console.WriteLine("## {0} ##", ex.GetType().Name);
}
}
產生的輸出在以下之間交替(不確定):
From 1st child
From 2nd child
** AggregateException **
ArgumentException
和
From 1t child
From 2nd child
** AggregateException **
NullReferenceException
似乎總是傳播/捕獲子任務之一的異常,並且只有一個例外。
為什么僅傳播/捕獲一種異常?
我會更好地理解,是否總是捕獲子任務中的任何異常或所有異常
在這種情況下,是否有可能同時捕獲全部異常或全部異常?
您不應將父/子任務與async
混合使用。 它們並非旨在一起使用。
svick已經回答了這個問題,作為他對其他問題的(正確)回答的一部分。 這是您如何想到的:
StartNew
都獲得一個異常,該異常被包裝到AggregateException
並放在返回的Task
。 StartNew
從其子任務中同時獲取兩個AggregateException
,並將其包裝在返回的Task
上的另一個AggregateException
。 await
Task
,會引發第一個內部異常。 其他任何人都將被忽略。 您可以通過保存Task
並在await
引發異常后檢查它們來觀察此行為:
async static Task Test()
{
Task containingTask, nullRefTask, argTask;
try
{
containingTask = Task.Factory.StartNew(() =>
{
nullRefTask = Task.Factory.StartNew(() =>
{
throw new NullReferenceException();
}, TaskCreationOptions.AttachedToParent);
argTask = Task.Factory.StartNew(() =>
{
throw new ArgumentException();
}, TaskCreationOptions.AttachedToParent);
});
await containingTask;
}
catch (AggregateException ex)
{
Console.WriteLine("** {0} **", ex.GetType().Name);
}
}
如果在WriteLine
上放置一個斷點,則可以看到兩個子任務的異常都放置在父任務上。 await
操作符僅傳播其中之一,因此這就是為什么您僅捕獲其中一個的原因。
從我可以推斷出發生這種情況的原因是,等待信號指示該任務等待任務完成。 當引發異常時,任務完成(因為異常使它崩潰),並且該異常向外傳播到將捕獲該異常的異步函數。 這意味着您將始終在此設置中遇到一個異常。
要始終捕獲兩者,請刪除await,而改用Task.Factory.StartNew(..)。Wait(); Wait函數將保留所有子進程的計數,直到所有子進程完成后才返回。 由於拋出了多個異常(每個孩子一個),因此將它們捆綁在一個新的AggregateException中,稍后將其捕獲並將其子對象展平並打印內部異常。 這應該給您輸出:
From 1st child
From 2nd child
** AggregateException **
ArgumentException
NullReferenceException
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.