Qual é a diferença entre Task.WaitAll()
e Task.WhenAll()
do CTP assíncrono? Você pode fornecer algum código de exemplo para ilustrar os diferentes casos de uso?
Qual é a diferença entre Task.WaitAll()
e Task.WhenAll()
do CTP assíncrono? Você pode fornecer algum código de exemplo para ilustrar os diferentes casos de uso?
Respostas:
Task.WaitAll
bloqueia o encadeamento atual até que tudo esteja completo.
Task.WhenAll
retorna uma tarefa que representa a ação de aguardar até que tudo esteja concluído.
Isso significa que, a partir de um método assíncrono, você pode usar:
await Task.WhenAll(tasks);
... o que significa que seu método continuará quando tudo estiver concluído, mas você não amarrará um fio para ficar por aqui até esse momento.
WhenAll
, mas isso não é o mesmo que bloquear o encadeamento.
Enquanto a resposta de JonSkeet explica a diferença de uma maneira tipicamente excelente, há outra diferença: tratamento de exceções .
Task.WaitAll
lança um AggregateException
quando qualquer uma das tarefas é lançada e você pode examinar todas as exceções lançadas. O await
in await Task.WhenAll
desembrulha o AggregateException
e 'retorna' apenas a primeira exceção.
Quando o programa abaixo é executado com await Task.WhenAll(taskArray)
a saída é o seguinte.
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.
Quando o programa abaixo é executado com Task.WaitAll(taskArray)
a saída é o seguinte.
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.
O 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
, não uma diferença entre os dois métodos. Ambos propagam um AggregateException
, jogando diretamente ou através de uma propriedade (a Task.Exception
propriedade).
Como exemplo da diferença - se você tem uma tarefa, faz algo com o thread da interface do usuário (por exemplo, uma tarefa que representa uma animação em um Storyboard) se você Task.WaitAll()
o thread da interface do usuário é bloqueado e a interface do usuário nunca é atualizada. se você usar await Task.WhenAll()
, o thread da interface do usuário não será bloqueado e a interface do usuário será atualizada.
O que eles fazem:
Qual é a diferença:
Use qual quando:
WaitAll
que eu entendo.
Task.WaitAll
depois de fazer algum outro trabalho? Quero dizer, em vez de chamá-lo logo após iniciar suas tarefas.