(并行编程)嵌套任务和子任务
嵌套任务和子任务
嵌套任务就是在另一个任务的用户委托中创建的 Task 实例。 子任务是使用 AttachedToParent 选项创建的嵌套任务。 一个任务可以创建任意数量的子任务和/或嵌套任务,该数量仅受系统资源限制。 下面的示例演示一个父任务,该父任务创建一个简单的嵌套任务。
static void SimpleNestedTask() { var parent = Task.Factory.StartNew(() => { Console.WriteLine("Outer task executing."); var child = Task.Factory.StartNew(() => { Console.WriteLine("Nested task starting."); Thread.SpinWait(500000); Console.WriteLine("Nested task completing."); }); }); parent.Wait(); Console.WriteLine("Outer has completed."); } /* Sample output: Outer task executing. Nested task starting. Outer has completed. Nested task completing. */
子任务与嵌套任务之间最主要的区别是:嵌套任务实质上独立于父任务或外部任务,而附加的子任务与父任务密切同步。如果将任务创建语句改为使用 AttachedToParent 选项(如下面的示例所示),
将生成以下输出。
您可以使用附加的子任务创建异步操作的紧密同步关系图。但是,在大多数情况下,因为与其他任务的关系不太复杂,所以建议使用嵌套任务。这就是默认情况下嵌套其他任务内创建的任务的原因,您必须显式指定 AttachedToParent 选项以创建子任务。
下表列出了两种子任务的基本区别。
|
类别 |
嵌套任务 |
附加的子任务 |
|---|---|---|
|
外部任务(父任务)等待内部任务完成。 |
否 |
是 |
|
父任务传播子任务(内部任务)引发的异常。 |
否 |
是 |
|
父任务(外部任务)的状态依赖于子任务(内部的任务)的状态。 |
否 |
是 |
在嵌套任务为 Task<TResult> 的分离方案中,您仍可以通过访问嵌套任务的 Result 属性来强制父任务等待子任务。 Result 属性处于阻止状态,直到其任务完成。
static void WaitForSimpleNestedTask() { var outer = Task<int>.Factory.StartNew(() => { Console.WriteLine("Outer task executing."); var nested = Task<int>.Factory.StartNew(() => { Console.WriteLine("Nested task starting."); Thread.SpinWait(5000000); Console.WriteLine("Nested task completing."); return 42; }); // Parent will wait for this detached child. return nested.Result; }); Console.WriteLine("Outer has returned {0}.", outer.Result); } /* Sample output: Outer task executing. Nested task starting. Nested task completing. Outer has returned 42. */
如果嵌套任务引发异常,必须像任何非嵌套任务一样,在外部任务中直接查看或处理该异常。如果附加的子任务引发异常,该异常会自动传播到父任务并传回等待或尝试访问该任务的 Result 属性的线程。因此,通过使用附加的子任务,您仅在一个位置点就可以处理所有异常,即在调用线程上调用 Wait。有关更多信息,请参见异常处理(任务并行库)。
请记住,任务取消是协作性的操作。因此,若要“可取消”,每个附加或分离的子任务必须监视取消标记的状态。如果要通过使用一个取消请求来取消父任务及其所有子任务,请将同一标记作为参数传递给所有任务,并在每个任务中提供逻辑以响应请求。有关更多信息,请参见任务取消和如何:取消任务及其子级。
父任务何时取消
如果父任务在子任务启动之前取消自己,则子任务(嵌套任务)将显然永远不会启动。如果父任务在子任务或嵌套任务启动后取消自己,则嵌套任务(子任务)将运行直到完成,除非它具有自己的取消逻辑。有关更多信息,请参见任务取消。
嵌套任务何时取消
如果分离的子任务通过使用传递给它的同一标记取消自己,且父任务不等待子任务,则不会传播异常,因为异常被视为良性协作取消。此行为与任何顶级任务的行为相同。
当附加的子任务通过使用传递给它的同一标记取消自己时,TaskCanceledException 传播到 AggregateException 内的联接线程。等待父任务非常重要,这样,除了可以处理通过附加子任务的关系图向上传播的所有出错异常,还可以处理向上传播的所有良性异常。
有关更多信息,请参见异常处理(任务并行库)。

浙公网安备 33010602011771号