run parallel method library example ejemplos create await async c# asynchronous async-await task-parallel-library

method - task parallel library c#



WaitAll vs WhenAll (4)

¿Cuál es la diferencia entre Task.WaitAll() y Task.WhenAll() desde el CTP asíncrono? ¿Puede proporcionar algún código de muestra para ilustrar los diferentes casos de uso?


Como ejemplo de la diferencia, si tiene una tarea, hace algo con el subproceso de la interfaz de usuario (p. Ej., Una tarea que representa una animación en un guión gráfico) si hace Task.WaitAll() entonces el subproceso de la interfaz de usuario se bloquea y la interfaz de usuario nunca es actualizado. si utiliza await Task.WhenAll() , el subproceso de la interfaz de usuario no se bloquea y la interfaz de usuario se actualizará.


Qué hacen:

  • Internamente ambos hacen lo mismo.

Cual es la diferencia:

  • WaitAll es una llamada de bloqueo
  • WhenAll - not - code continuará ejecutándose

Utilice que cuando

  • WaitAll cuando no puede continuar sin tener el resultado
  • Cuando todo lo que acaba de ser notificado, no bloqueado

Si bien la respuesta de JonSkeet explica la diferencia de una manera típicamente excelente para mí, la mayor diferencia práctica es el manejo de excepciones .

Task.WaitAll lanza una Task.WaitAll AggregateException cuando cualquiera de las tareas se lanza y puede examinar todas las excepciones lanzadas. La await en la await Task.WhenAll la await Task.WhenAll AggregateException y ''devuelve'' solo la primera excepción.

Cuando el siguiente programa se ejecuta con await Task.WhenAll(taskArray) la salida es la siguiente.

19/11/2016 12:18:37 AM: Task 1 started 19/11/2016 12:18:37 AM: Task 3 started 19/11/2016 12:18:37 AM: Task 2 started Caught Exception in Main at 19/11/2016 12:18:40 AM: Task 1 throwing at 19/11/2016 12:18:38 AM Done.

Cuando el programa siguiente se ejecuta con Task.WaitAll(taskArray) el resultado es el siguiente.

19/11/2016 12:19:29 AM: Task 1 started 19/11/2016 12:19:29 AM: Task 2 started 19/11/2016 12:19:29 AM: Task 3 started Caught AggregateException in Main at 19/11/2016 12:19:32 AM: Task 1 throwing at 19/11/2016 12:19:30 AM Caught AggregateException in Main at 19/11/2016 12:19:32 AM: Task 2 throwing at 19/11/2016 12:19:31 AM Caught AggregateException in Main at 19/11/2016 12:19:32 AM: Task 3 throwing at 19/11/2016 12:19:32 AM Done.

El programa:

class MyAmazingProgram { public class CustomException : Exception { public CustomException(String message) : base(message) { } } static void WaitAndThrow(int id, int waitInMs) { Console.WriteLine($"{DateTime.UtcNow}: Task {id} started"); Thread.Sleep(waitInMs); throw new CustomException($"Task {id} throwing at {DateTime.UtcNow}"); } static void Main(string[] args) { Task.Run(async () => { await MyAmazingMethodAsync(); }).Wait(); } static async Task MyAmazingMethodAsync() { try { Task[] taskArray = { Task.Factory.StartNew(() => WaitAndThrow(1, 1000)), Task.Factory.StartNew(() => WaitAndThrow(2, 2000)), Task.Factory.StartNew(() => WaitAndThrow(3, 3000)) }; Task.WaitAll(taskArray); //await Task.WhenAll(taskArray); Console.WriteLine("This isn''t going to happen"); } catch (AggregateException ex) { foreach (var inner in ex.InnerExceptions) { Console.WriteLine($"Caught AggregateException in Main at {DateTime.UtcNow}: " + inner.Message); } } catch (Exception ex) { Console.WriteLine($"Caught Exception in Main at {DateTime.UtcNow}: " + ex.Message); } Console.WriteLine("Done."); Console.ReadLine(); } }


Task.WaitAll bloquea el hilo actual hasta que todo se haya completado.

Task.WhenAll devuelve una tarea que representa la acción de esperar hasta que todo se haya completado.

Eso significa que desde un método asíncrono, puedes usar:

await Task.WhenAll(tasks);

... lo que significa que su método continuará cuando todo se haya completado, pero no atará un hilo para quedarse solo hasta ese momento.