2012-02-17 3 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, все это связано с изменениями, которые не могут быть включены в основные функции .NET для CTP, но будут правильно установлены для окончательной версии. –

+0

Изменена 'Задача .RunEx' to 'TaskEx.RunEx' В классе Async CTP' Task' нет ни 'Run()', ни 'RunEx()'). Они оба находятся в 'TaskEx'. Исправьте меня, если я ошибаюсь –

ответ

0

Task.Run порождает новую тему в большинстве сценариев, насколько я ее понимаю.

Важно отметить, что просто потому, что вы отмечаете метод async и используете awaiters, это НЕ (обязательно) означает, что новые потоки создаются, завершение запланировано в SAME, исполняемом, из которого они были вызваны во многих случаях.

Трюк здесь связан с плановым контентом. Если он настроен на многопоточную квартиру, то вы собираетесь делегировать доработки жизнеспособным потокам в threadpool. Если вы находитесь в однопотоковой квартире, как и весь код интерфейса WPF и WinForms, то он вернется в вызывающий поток для завершения, что позволит выполнять работу непосредственно в пользовательском интерфейсе без видимой сортировки потока в коде.

+0

'Task.Run' очереди в пуле потоков, который обычно не запускает новый поток. 'await' расставляет свои продолжения в свой текущий' SynchronizationContext' или 'TaskScheduler' (не поток) - см. конец [этой статьи] (http://msdn.microsoft.com/en-us/magazine/gg598924.aspx) который по-прежнему применяется с CTP v3 (и предварительный просмотр VS11 dev). Я также рассматриваю асинхронный контекст в [моем async intro post] (http://nitoprograms.blogspot.com/2012/02/async-and-await.html).Этот контекст не имеет ничего общего с MTA или STA, хотя возможен контекст, поддерживающий STA или MTA. –

+0

Я стою приятно исправлено: D – Firoso

11

Используйте TaskEx.Run, если вы хотите запустить синхронный код в контексте пула потоков.

Используйте TaskEx.RunEx, если вы хотите запустить асинхронный код в контексте пула потоков.

Стивен Toub имеет два блога, связанные с различием в поведении:

Это только один из нескольких вариантов у вас есть для creating tasks. Если вам не нужно использовать Run/RunEx, вам не следует. Используйте простые методы async и используйте только Run/RunEx, если вам нужно что-то запустить в фоновом режиме.

+0

На самом деле это не так ... RunEx имеет отношение к значению, возвращающему лямбда-выражения ... не асинхронному. Run запускает асинхронную лямбду. – Firoso

+2

В .Net 4.5 DP, кажется, есть только 'Task.Run()', no 'Ex'es. – svick

+4

TaskEx находится только в CTP. В .Net 4.5 методы TaskEx были интегрированы в Task. – Phil

1

Разница между двумя методами DoWork() заключается в том, что первый (который использует TaskEx.RunEx()) не является асинхронным вообще. Он выполняется полностью синхронно, запускает другую задачу в другом потоке и немедленно возвращает завершенный Task. Если вы задали await ed или Wait(), это не будет дождитесь завершения внутренней задачи.

Смежные вопросы