2014-09-05 86 views
5

我有这样的例子代码:ContinueWith链接无法正常运行

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和处理everythning我自己,但它只是不起作用...

+0

等待声明“分裂”任务。所以t1只会引用前半部分。我感到惊讶放入假处理2放入假处理后不立即发生1 – 2014-09-05 17:17:02

+0

@WeylandYutani我在答案中解释了为什么这种情况没有发生。 – Servy 2014-09-05 17:18:20

+0

其实我还在说垃圾,所以不理我 – 2014-09-05 17:19:36

回答

8

看看t2的类型。这是一个Task<Task>t2将完成,当它完成开始执行实际工作的任务时,该工作实际完成。

要让代码正常工作,对代码进行的最小更改是在第二次和第三次调用ContinueWith之后添加unwrap,以便完成表示完成工作的任务。

更习惯的解决方案将完全删除ContinueWith调用,只是使用await添加延续任务。

有趣的是,你会看到相同的行为t1如果使用Task.Factory.StartNew,但Task.Run是专门设计与async lambda表达式的工作,实际上在内部解开所有Action<Task>代表返回任务的返回结果,而不是任务代表开始该任务,这就是为什么你不需要解开这个任务。

+0

谢谢,解包工作(不能使用await,因为真正的代码不是线性列表,我正在接收连续执行的任务流,所以需要排队等待。当然,我会喜欢用await代替: ))。 – 2014-09-05 17:27:57

+0

@MartinSykora是的,你*可以*使用'await'而不是'ContinueWith',虽然很难告诉你如何不知道你的情况的具体情况。最有可能的是,您只需编写一个接受任务的“异步”方法,等待它,并等待其他事情并调用其他方法,然后返回一个“任务”。几乎每次你在一个任务上调用'ContinueWith'时,你都可以调用'await'来代替它,并且让它更好,只有极少数例外。 – Servy 2014-09-05 17:43:45

2

在现实中,我排队进入的任务(一些异步的,有些不是),并希望在他们来以相同的顺序,但没有并行

你可能想使用TPL数据流为执行这些那。具体而言,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); 
+0

不错,那可能正是我所需要的,如果它有效的话,绝对会更优雅:-) – 2014-09-07 15:55:13