【问题标题】:What's the difference between these three Task Continuations?这三个任务继续有什么区别?
【发布时间】:2015-02-14 13:58:23
【问题描述】:

我有这两种情况,但我不明白为什么会这样:

    static void Main(string[] args)
    {
        Console.WriteLine("***Starting T1");
        //run two tasks sequentially
        Task t = FirstTask().ContinueWith(_ => SecondTask(), TaskContinuationOptions.OnlyOnRanToCompletion);
        //register succeded and faulted continuations
        t.ContinueWith(_ => Completion(), TaskContinuationOptions.OnlyOnRanToCompletion);
        t.ContinueWith(_ => Faulted(), TaskContinuationOptions.OnlyOnFaulted);
        Console.ReadLine();
        Console.WriteLine("***Starting T2");
        Task t2 = FirstTask().ContinueWith(_ => FaultTask(), TaskContinuationOptions.OnlyOnRanToCompletion);
        t2.ContinueWith(_ => Completion(), TaskContinuationOptions.OnlyOnRanToCompletion);
        t2.ContinueWith(_ => Faulted(), TaskContinuationOptions.OnlyOnFaulted);
        Console.ReadLine();
        Console.WriteLine("***Starting T3");
        Task t3 = FirstTask().ContinueWith(ant => ant.ContinueWith(_ => FaultTask(), TaskContinuationOptions.OnlyOnRanToCompletion));
        t3.ContinueWith(_ => Completion(), TaskContinuationOptions.OnlyOnRanToCompletion);
        t3.ContinueWith(_ => Faulted(), TaskContinuationOptions.OnlyOnFaulted);
        Console.ReadLine();
    }

    private static Task FirstTask()
    {
        return Task.Run(() =>
        {
            Console.WriteLine("Task 1");
            Thread.Sleep(1000);
        });
    }

    private static Task SecondTask()
    {
        return Task.Run(() =>
        {
            Console.WriteLine("Task 2");
            Thread.Sleep(1000);
        });
    }

    private static Task FaultTask()
    {
        return Task.Run(() =>
        {
            Console.WriteLine("Throw...");
            Thread.Sleep(1000);
            throw new ArgumentException();
        });
    }

    private static void Completion()
    {
        Console.WriteLine("Complete");
    }

    private static void Faulted()
    {
        Console.WriteLine("Faulted");
    }

在情况 1 中,事情按预期运行。但是,如果删除FirstTask()中的Sleep(),则不能保证任务按顺序运行。

在情况 2 中,Faulted() 处理程序未运行。我预计会发生这种情况,因为有一个未处理的异常。

在情况 3 中,在运行 Complete() 处理程序后引发异常。我对为什么会发生这种排序感到困惑。

基本上,我希望能够链接尽可能多的任务,并让它们在前一个任务完成后按顺序运行。一旦我创建了链,我将显示一个等待表单并将OnlyOnRanToCompletionOnlyOnCancelledOnlyOnFaulted 的延续注册到最终任务(阅读:全部完成)以关闭表单 - 显示成功或错误.

这是 MSDN 指的是那些不可用于多任务延续的选项吗?

【问题讨论】:

  • 两个任务ran to completion。投票关闭,因为无法复制。一旦你用可以重现问题的代码更新问题,就会收回。我怀疑您的原始代码会设置一些您没有向我们展示的继续标志。
  • 您的代码仍然不会显示所描述的行为。请在发布之前运行代码并测试自己。谢谢。
  • 您能否发布演示问题所需的代码,以便我可以将代码复制并粘贴到控制台应用程序中并运行?目前第一个任务甚至无法编译。
  • @Simon,每当你调用Task.Run(),你的任务已经开始了。因此,例如,在第一行代码中,您同时启动了两个任务
  • 啊,是的,谢谢 Zruty

标签: c# multithreading task-parallel-library task continuations


【解决方案1】:

您在tt2 上的返回类型是Task<Task> 而不仅仅是一个任务。 T3 是Task<Task<Task>>。要获得所需的行为,您应该能够Unwrap这些任务,这将为您提供代表整个操作的任务(阅读文档以获取更多信息):

Console.WriteLine("***Starting T1");
//run two tasks sequentially
Task<Task> t = FirstTask().ContinueWith(_ => SecondTask(), TaskContinuationOptions.OnlyOnRanToCompletion);

//register succeded and faulted continuations
t.Unwrap().ContinueWith(_ => Completion(), TaskContinuationOptions.OnlyOnRanToCompletion);
t.Unwrap().ContinueWith(_ => Faulted(), TaskContinuationOptions.OnlyOnFaulted);

Console.ReadLine();
Console.WriteLine("***Starting T2");

Task<Task> t2 = FirstTask().ContinueWith(_ => FaultTask(), TaskContinuationOptions.OnlyOnRanToCompletion);
t2.Unwrap().ContinueWith(_ => Completion(), TaskContinuationOptions.OnlyOnRanToCompletion);
t2.Unwrap().ContinueWith(_ => Faulted(), TaskContinuationOptions.OnlyOnFaulted);
Console.ReadLine();

我建议尽可能使用 async/await 模式,因为它可以更轻松地处理此类任务。

【讨论】:

  • 谢谢,是的,我理解正常我可以使用:await t1; await t2; await t3;,但是检查任务完成状态有点麻烦
  • @Simon,你为什么认为它更麻烦?它当然更具可读性。最有可能的是,无论您认为使用 async/await 方法更麻烦的是什么,都可以通过一两个辅助方法来解决。
  • 解决方案仅在第一次运行成功时执行t2,或者仅在第一次发生故障时 IMO 可读性较差时才运行t3。您必须持有对Task 的引用,然后执行if
猜你喜欢
  • 1970-01-01
  • 2013-06-23
  • 2015-12-17
  • 1970-01-01
  • 2011-11-05
  • 2017-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多