为什么只有一个从孩子的任务很多例外总是能够传播? [英] Why is only one from many exceptions from child tasks always propagated?

查看:118
本文介绍了为什么只有一个从孩子的任务很多例外总是能够传播?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在努力更好地把握异常和错误的TPL处理(并在.NET一些运气4.5异步/等待的任务)

I am struggling to better grasp the rationale of exception and error handling in TPL (and with some more luck in .NET 4.5 async/await tasks)

在略有我刚才的问题<修改href=\"http://stackoverflow.com/questions/16571791/how-to-better-understand-the-$c$c-statements-from-async-handling-multiple-exc#16571791\">\"How更好地了解code /从报表异步 - 处理多个异常文章 C#控制台应用程序,code运行2 分离内部嵌套附后(相关的)子(?更新:对不起,开始了一个问题,而是由另一端)的任务:

The slightly modified from my earlier question "How to better understand the code/statements from "Async - Handling multiple Exceptions" article?" C# console app code running 2 detached inner nested attached (dependent) child (Update: sorry, started one question but ended by another!) tasks:

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);
    }
 } 

产生输出交替(不确定性)之间:

produces output that alternates (non-deterministically) between:

From 1st child
From 2nd child
** AggregateException **
ArgumentException

From 1t child
From 2nd child
** AggregateException **
NullReferenceException

好像总有一个和始终传播/抓到一个小孩在任务之一,只有一个例外。

Seems like always one and only one exception from one of a child tasks always propagated/caught.

为什么只有一个例外传播/抓到?结果
我会更好地理解,如果没有或者说从子任务的所有异常总是陷入

Why is only one exception propagated/caught?
I'd have better understood if none or rather all exceptions from child tasks are always caught

是否有可能,在这种情况下,双方还是无一例外会被抓?

Is it possible, in this situation, that both or none exception will be caught?

推荐答案

您不应该异步混合使用父/子任务。他们的目的不是要一起去。

You should not mix parent/child tasks with async. They were not designed to go together.

他(正确的)回答您的其他问题 svick已经回答了这个问题。这里是你如何能想起来:

svick already answered this question as part of his (correct) answer to your other question. Here's how you can think of it:


  • 每个内部 StartNew 得到一个例外,它包装成一个 AggregateException ,并放置在返回任务

  • StartNew 从其子任务,它包装成另一种获得两个 AggregateException 取值 AggregateException 它返回工作

  • 的await A 工作,第一内异常。任何人都会被忽略。

  • Each inner StartNew gets one exception, which is wrapped into an AggregateException and placed on the returned Task.
  • The outer StartNew gets both AggregateExceptions from its child tasks, which it wraps into another AggregateException on its returned Task.
  • When you await a Task, the first inner exception is raised. Any others are ignored.

您可以通过保存工作和检查它们的异常是由复活以后,伺机观察此行为

You can observe this behavior by saving the Tasks and inspecting them after the exception is raised by 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 断点,你可以看到,从两个孩子的任务异常被放置在父任务。在等待操作人员只需传播其中之一,所以这就是为什么你只能望尘莫及的。

If you put a breakpoint on WriteLine, you can see that the exceptions from both child tasks are being placed on the parent task. The await operator only propagates one of them, so that's why you only catch one.

这篇关于为什么只有一个从孩子的任务很多例外总是能够传播?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆