2012-02-17 16 views
7

Estoy tratando de entender cuándo usar TaskEx.Run. He proporcionado dos ejemplos de código que escribí a continuación que producen el mismo resultado. Lo que no veo es por eso que tomaría el Task.RunExTaskEx.RunEx enfoque , estoy seguro de que hay una buena razón y estaba esperando que alguien me podría llenar.Cuándo utilizar TaskEx.Run frente a 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(); 
    } 
} 

que pueden lograr los mismos resultados al igual que

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

El hilo anterior es una discusión sobre los motivos de TaskEx.RunEx, todo tiene que ver con cambios que no podrían incluirse en la funcionalidad .NET central para el CTP, pero se integrará correctamente para la versión final –

+0

'Tarea' .RunEx' to 'TaskEx.RunEx' No hay' Run() 'ni' RunEx() 'en la clase Async CTP' Task'. Ambos están en 'TaskEx'. Corrígeme, si estoy equivocado –

Respuesta

0

Tarea.Run crea un nuevo hilo en la mayoría de los escenarios, tal como lo entiendo.

Es importante tener en cuenta que simplemente porque marque un método como asincrónico y use awaiters, esto NO (necesariamente) significa que se están creando nuevos subprocesos, las terminaciones se programan en el MISMO subproceso de ejecución del que fueron llamados en muchos casos.

El truco aquí tiene que ver con el SchedulingContext. Si está configurado para un apartamento multiproceso, entonces delegará terminaciones a hilos viables en el grupo de subprocesos. Si se encuentra en un apartamento singlethreaded como todo el código UI de WPF y WinForms, se volverá a completar la cadena de llamadas para permitir que el trabajo se realice directamente en la interfaz de usuario sin que el código visible se agrupe en el código.

+0

'Task.Run' colas en el grupo de subprocesos, que generalmente no inicia un nuevo subproceso. 'await' programa sus continuaciones a su actual' SynchronizationContext' o 'TaskScheduler' (no thread) - vea el final de [este artículo] (http://msdn.microsoft.com/en-us/magazine/gg598924.aspx) que todavía se aplica a partir de CTP v3 (y vista previa de desarrollo VS11). También cubro el contexto asíncrono en [mi intro post astro] (http://nitoprograms.blogspot.com/2012/02/async-and-await.html).Este contexto no tiene nada que ver con MTA o STA, aunque es posible tener un contexto que soporte STA o MTA. –

+0

Me encuentro gratamente corregido: D – Firoso

11

Use TaskEx.Run cuando desee ejecutar código síncrono en un contexto de grupo de subprocesos.

Use TaskEx.RunEx cuando desee ejecutar un código asíncrono en un contexto de grupo de subprocesos.

Stephen Toub tiene dos entradas de blog relacionadas con la diferencia de comportamiento:

esto es sólo una de las varias opciones que tiene para creating tasks. Si no tiene que usar Run/RunEx, entonces no debería. Use los métodos simples async, y solo use Run/RunEx si necesita ejecutar algo en segundo plano.

+0

En realidad eso no es verdad ... RunEx tiene que ver con el valor de devolver expresiones lambda ... no asincronía. Ejecutar controladores async lambda está bien. – Firoso

+2

En .Net 4.5 DP, parece haber solo 'Task.Run()', no 'Ex'es. – svick

+4

TaskEx solo está en el CTP. En .Net 4.5 los métodos en TaskEx se han integrado en Tarea. – Phil

1

La diferencia entre sus dos métodos DoWork() es que el primero (que usa TaskEx.RunEx()) no es asíncrono en absoluto. Se ejecuta de forma totalmente sincrónica, inicia la otra tarea en otro subproceso e inmediatamente devuelve un Task completado. Si await ed o Wait() ed en esa tarea, no esperaría hasta que se complete la tarea interna.

Cuestiones relacionadas