Ответы:
Task.WaitAll блокирует текущий поток, пока все не завершится.
Task.WhenAllвозвращает задачу, которая представляет действие ожидания, пока все не будет завершено.
Это означает, что из асинхронного метода вы можете использовать:
await Task.WhenAll(tasks);
... что означает, что ваш метод продолжится, когда все будет завершено, но вы не будете связывать поток, чтобы просто торчать до этого времени.
WhenAll, но это не то же самое, что блокирование потока.
Хотя ответ JonSkeet объясняет разницу, как правило, превосходно, есть еще одно отличие: обработка исключений .
Task.WaitAllБросает, AggregateExceptionкогда выбрасывает любое из заданий, и вы можете проверить все сгенерированные исключения. Оператор awaitin await Task.WhenAllразворачивает AggregateExceptionи возвращает только первое исключение.
Когда программа, представленная ниже, выполняется с await Task.WhenAll(taskArray)выводом следующим образом.
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.
Когда нижеприведенная программа выполняется с Task.WaitAll(taskArray)выходом следующим образом.
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.
Программа:
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;противawait Task.WhenAll(t1,t2,t3);
await, а не разница между этими двумя методами. Оба распространяют AggregateException, либо выбрасывая напрямую, либо через свойство ( Task.Exceptionсвойство).
В качестве примера различия - если у вас есть задача, она делает что-то с потоком пользовательского интерфейса (например, задача, которая представляет анимацию в раскадровке), если вы Task.WaitAll()тогда поток пользовательского интерфейса блокируется, и пользовательский интерфейс никогда не обновляется. если вы используете, await Task.WhenAll()тогда поток пользовательского интерфейса не блокируется, и пользовательский интерфейс будет обновлен.
Что они делают:
Какая разница:
Используйте, когда:
WaitAllкак я понимаю.
Task.WaitAll после того, как вы сделали свою другую работу? Я имею в виду, вместо того, чтобы называть это сразу после запуска ваших задач.