¿Cuál es la diferencia entre Task.WaitAll()
y Task.WhenAll()
desde el Async CTP? ¿Puede proporcionar algún código de muestra para ilustrar los diferentes casos de uso?
¿Cuál es la diferencia entre Task.WaitAll()
y Task.WhenAll()
desde el Async CTP? ¿Puede proporcionar algún código de muestra para ilustrar los diferentes casos de uso?
Respuestas:
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, puede usar:
await Task.WhenAll(tasks);
... lo que significa que su método continuará cuando todo esté completo, pero no atará un hilo para quedarse hasta ese momento.
WhenAll
, pero eso no es lo mismo que bloquear el hilo.
Si bien la respuesta de JonSkeet explica la diferencia de una manera típicamente excelente, hay otra diferencia: el manejo de excepciones .
Task.WaitAll
lanza un AggregateException
cuando se lanza cualquiera de las tareas y puede examinar todas las excepciones lanzadas. El await
en await Task.WhenAll
desenvuelve los AggregateException
y 'devuelve' sólo la primera excepción.
Cuando el siguiente programa se ejecuta con await Task.WhenAll(taskArray)
la salida es el 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 siguiente programa se ejecuta con Task.WaitAll(taskArray)
la salida es la 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();
}
}
await t1; await t2; await t3;
vsawait Task.WhenAll(t1,t2,t3);
await
, no una diferencia entre los dos métodos. Ambos propagan un AggregateException
, lanzando directamente o a través de una propiedad (la Task.Exception
propiedad).
Como ejemplo de la diferencia: si tiene una tarea, hace algo con el hilo de la interfaz de usuario (por ejemplo, una tarea que representa una animación en un guión gráfico) si Task.WaitAll()
luego el hilo de la interfaz de usuario está bloqueado y la interfaz de usuario nunca se actualiza. si lo usa await Task.WhenAll()
, el hilo de la interfaz de usuario no está bloqueado y la interfaz de usuario se actualizará.
Qué hacen:
Cual es la diferencia:
Use cual cuando:
WaitAll
que yo entiendo.
Task.WaitAll
después de que hiciste tu otro trabajo? Quiero decir, en lugar de llamarlo justo después de comenzar tus tareas.