2012-02-17 55 views
7

我試圖瞭解何時使用TaskEx.Run。我提供了兩個我寫在下面的代碼示例,可以產生相同的結果。我看不出就是爲什麼我會採取 Task.RunExTaskEx.RunEx方法,我敢肯定有一個很好的理由,並希望有人能填補我進去。何時使用TaskEx.Run與TaskEx.RunEx

async Task DoWork(CancellationToken cancelToken, IProgress<string> progress) 
{ 
    int i = 0; 
    TaskEx.RunEx(async() => 
     { 
      while (!cancelToken.IsCancellationRequested) 
      { 
       progress.Report(i++.ToString()); 
       await TaskEx.Delay(1, cancelToken); 
      } 
     }, cancelToken); 
} 
private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    if (button.Content.ToString() == "Start") 
    { 
     button.Content = "Stop"; 
     cts.Dispose(); 
     cts = new CancellationTokenSource(); 
     listBox.Items.Clear(); 
     IProgress<string> progress = new Progress<string>(s => 
     { 
      listBox.Items.Add(s); 
      listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]); 
     }); 
     DoWork(cts.Token, progress); 
    } 
    else 
    { 
     button.Content = "Start"; 
     cts.Cancel(); 
    } 
} 

我可以達到同樣的效果像這樣

async Task DoWork(CancellationToken cancelToken) 
    { 
     int i = 0; 
     while (!cancelToken.IsCancellationRequested) 
     { 
      listBox.Items.Add(i++); 
      listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]); 
      await TaskEx.Delay(100, cancelToken); 

     } 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     if (button.Content.ToString() == "Start") 
     { 
      button.Content = "Stop"; 
      cts.Dispose(); 
      cts = new CancellationTokenSource(); 
      listBox.Items.Clear(); 
      DoWork(cts.Token); 
     } 
     else 
     { 
      button.Content = "Start"; 
      cts.Cancel(); 
     } 
    } 
+0

上述線程討論了TaskEx.RunEx的原因,它的所有變化都無法放入CTP的核心.NET功能中,但會被正確集成以供最終版本發佈 – 2012-02-17 20:27:10

+0

已更改'任務.RunEx'到'TaskEx.RunEx'在Async CTP'Task'類中沒有'Run()'和'RunEx()'。他們都在'TaskEx'中。糾正我,如果我錯了 – 2013-04-10 04:35:47

回答

0

Task.Run在大多數情況下產生一個新的線程,據我所知。

重要的是要注意,僅僅因爲你將一個方法標記爲async並使用awaiters,這並不(必然)意味着正在創建新線程,完成將安排在執行的SAME線程上,在許多情況下。

這裏的技巧與SchedulingContext有關。如果它被設置爲一個多線程的公寓,那麼你將完成委託給線程池中的可行線程。如果您位於單線程公寓中,因爲所有WPF和WinForms UI代碼都位於單線程中,那麼它將返回到調用線程以完成,從而允許直接在UI上完成工作,而不在代碼中顯示線程編組。

+0

'Task.Run'排隊到線程池,通常不啓動一個新的線程。 'await'將它的延續安排到當前的'SynchronizationContext'或'TaskScheduler'(不是線程) - 請參閱[本文]的末尾(http://msdn.microsoft.com/zh-cn/magazine/gg598924.aspx)這仍然適用於CTP v3(和VS11 dev預覽版)。我還介紹了[我的異步介紹帖子]中的異步上下文(http://nitoprograms.blogspot.com/2012/02/async-and-await.html)。此上下文與MTA或STA沒有任何關係,儘管可能有支持STA或MTA的上下文。 – 2012-02-18 00:35:17

+0

我站好了更正:D – Firoso 2012-02-21 17:29:06

11

當您想要在線程池上下文中運行同步代碼時,請使用TaskEx.Run。當您想要在線程池上下文中運行異步代碼時,請使用。

斯蒂芬Toub在行爲相關的差的兩個博客文章:

這只是你有幾個creating tasks選項之一。如果你不必使用Run/RunEx,那麼你不應該這樣做。如果您需要在後臺運行某些內容,請使用簡單的async方法,並僅使用Run/RunEx

+0

其實這不是真的...... RunEx與值返回lambda表達式...不異步。運行異步lambda的處理就好了。 – Firoso 2012-02-17 20:41:01

+2

在.Net 4.5 DP中,似乎只有'Task.Run()',沒有'Ex'es。 – svick 2012-02-17 22:43:31

+4

TaskEx僅在CTP中。在.Net 4.5中,TaskEx中的方法已被集成到Task中。 – Phil 2012-02-17 23:34:11

1

您的兩個DoWork()方法之間的區別在於第一個方法(使用TaskEx.RunEx())根本不是異步的。它完全同步執行,在另一個線程上啓動另一個任務,並立即返回一個完成的Task。如果您在該任務上編輯await ed或Wait(),則不會等待內部任務完成。