继续链接不按预期工作

时间:2014-09-05 17:06:03

标签: c# task-parallel-library task

我有这个示例代码:

    static void Main(string[] args) {
        var t1 = Task.Run(async () => {
            Console.WriteLine("Putting in fake processing 1.");
            await Task.Delay(300);
            Console.WriteLine("Fake processing finished 1. ");
        });
        var t2 = t1.ContinueWith(async (c) => {
            Console.WriteLine("Putting in fake processing 2.");
            await Task.Delay(200);
            Console.WriteLine("Fake processing finished 2.");
        });
        var t3 = t2.ContinueWith(async (c)  => {
            Console.WriteLine("Putting in fake processing 3.");
            await Task.Delay(100);
            Console.WriteLine("Fake processing finished 3.");
        });
        Console.ReadLine();
    }

控制台输出让我感到困惑:

  • 进行虚假处理1.
  • 假加工完成1。
  • 进行虚假处理2.
  • 进行虚假处理3.
  • 假加工结束3。
  • 假加工完成2。

我正在尝试将任务链接起来,以便一个接一个地执行,我做错了什么?而且我不能使用await,这只是示例代码,实际上我正在排队传入的任务(有些是异步的,有些不是)并且想要按照它们进入的相同顺序执行它们但没有并行性,ContinueWith似乎更好而不是创建一个ConcurrentQueue并自己处理每一个,但它只是不起作用......

2 个答案:

答案 0 :(得分:9)

看一下t2的类型。这是一个Task<Task>。完成启动执行实际工作的任务后,将完成

对您的代码进行的最小改动是在第二次和第三次调用t2之后添加unwrap,以便您完成代表完成的任务你的工作。

更惯用的解决方案是简单地完全删除ContinueWith次调用,只需使用ContinueWith为任务添加延续。

有趣的是,如果您使用await,您会看到t1的相同行为,但Task.Factory.StartNew专门用于处理Task.Run lambdas并实际内部解开所有内容async委托返回返回任务的结果,而不是代表启动该任务的任务,这就是您不需要打开该任务的原因。

答案 1 :(得分:2)

  

实际上我正在排队传入的任务(一些是异步的,一些不是),并希望按照它们进入但没有并行性的相同顺序执行它们

您可能希望使用TPL Dataflow。具体而言,ActionBlock

var block = new ActionBlock<object>(async item =>
{
  // Handle synchronous item
  var action = item as Action;
  if (action != null)
    action();

  // Handle asynchronous item
  var func = item as Func<Task>;
  if (func != null)
    await func();
});

// To queue a synchronous item
Action synchronous = () => Thread.Sleep(1000);
block.Post(synchronous);

// To queue an asynchronous item
Func<Task> asynchronous = async () => { await Task.Delay(1000); };
blockPost(asynchronous);