【问题标题】:TPL Continuation task: not sure who is the parent taskTPL 延续任务:不确定谁是父任务
【发布时间】:2023-03-29 17:53:01
【问题描述】:

我在使用 ContinuationOption.AttachedToParent 标志时遇到问题。

这是我的伪代码:

   Task parentTask = Task.Start(() =>   
   { 
        Task childTask = Task.Start(() => doSomething(),
                                    ContinuationOption.AttachedToParent);
        childTask.ContinueWith(() => followingMethod(),  
                                    ContinuationOption.AttachedToParent);
   }

我知道如果“doSomething()”抛出并且异常 childTask 失败并且 parentTask 也失败,因为 ContinuationOption.AttachedToParent 选项。

如果 followingMethod() 抛出异常,但 parentTask 状态为 Completed,我会期待相同的行为。

是我做错了还是延续任务的“父”任务不是我的“父任务”?

【问题讨论】:

    标签: c# .net task-parallel-library task continuations


    【解决方案1】:

    您的直觉是正确的,但我猜您很可能只是使用了错误的 API。

    我知道这只是伪代码,但Task.Start() 是一个实例方法,而不是静态方法,所以它不会按照您指示的方式编译,我们不知道您实际上是如何开始的任务和细节确实很重要。 TaskFactory.StartNew 会做你想做的事,但Task.Run 不会。试试这个:

    Task parent = Task.Factory.StartNew(() =>
    {
      Task child = Task.Factory.StartNew(
         () => { Console.WriteLine("foo"); },
         TaskCreationOptions.AttachedToParent);
      Task continuation = child.ContinueWith(
         (Task prev) => { throw new InvalidOperationException("Test"); },
         TaskContinuationOptions.AttachedToParent);
    });
    try
    {
      parent.Wait();
    }
    catch (AggregateException ex)
    {
      if (ex.Flatten().InnerException is InvalidOperationException)
      { 
        Console.WriteLine("The continuation exception was propagated to parent");
      }
    }
    

    如果你改变了

    Task parent = Task.Factory.StartNew(...)
    

    Task parent = Task.Run(...)
    

    那么您将无法获得您想要的行为,因为Task.Run 本质上是TaskFactory.StartNew 的包装器,它(除其他外)指定TaskCreationOptions.DenyChildAttach,因此两个嵌套任务都将分离运行(没有父级)。我猜这就是你的问题。

    【讨论】:

    • StartNew 应与显式任务调度程序一起使用
    【解决方案2】:

    此上下文中的父任务是您在 inside 中创建子任务的任务,就像在 Task.Factory.StartNew 中的 Task.Factory.StartNew 中一样。

    子任务(或嵌套任务)是在另一个任务的用户委托中创建的 System.Threading.Tasks.Task 实例,该任务称为父任务。子任务可以分离或附加。分离的子任务是独立于其父任务执行的任务。附加子任务是使用 TaskCreationOptions.AttachedToParent 选项创建的嵌套任务。

    Attached and Detached Child Tasks

    当您注册任务的延续时,该任务是先行任务,而不是父任务。 当您致电ContinueWith 时,您会得到一个代表继续的任务。这是您需要检查异常的任务:

    var continuation = task.ContinueWith(() => followingMethod());
    

    【讨论】:

    • 我知道 childTask 是 continuationTask 的前身,这就是我想要的“链”。困扰我的是,如果 continuationTask 失败 parentTask 不会失败(而如果 childTask 失败,则父任务也会失败)。当我的第二代任务都被标记为附加时,我的第二代任务应该以相同的方式影响我的第一代任务。
    • @user3798930 好吧,.Net 的设计者显然不同意。 childTask 在您的情况下永远不是父母。延续将附加到父级parentTask
    • 我不认为他曾经暗示 childTask 应该是父母。延续任务可以同时具有前项(childTask)和父项(parentTask),并且附加子任务中的异常会传播回父任务,而不管其前项如何。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-29
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多