2014-09-05 88 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