WaitAll vs WhenAll
В чем разница между Task.WaitAll()
и Task.WhenAll()
от Async CTP? Можете ли вы предоставить примерный код для иллюстрации различных вариантов использования?
- Разница между TPL и async / await (Обработка streamов)
- Лучший способ конвертировать метод async на основе обратного вызова в ожидаемую задачу
- Каков правильный способ отмены асинхронной операции, которая не принимает CancellationToken?
- Как ограничить количество одновременных операций асинхронного ввода-вывода?
- Отмена ожидающей задачи синхронно в streamе пользовательского интерфейса
- Секвенирование и реорганизация задач
- Запуск нескольких задач async и ожидание их завершения
- Выполнение задач параллельно
Task.WaitAll
блокирует текущий stream, пока все не завершится.
Task.WhenAll
возвращает задачу, которая представляет действие ожидания до тех пор, пока все не завершится.
Это означает, что из метода async вы можете использовать:
await Task.WhenAll(tasks);
… что означает, что ваш метод будет продолжаться, когда все будет завершено, но вы не будете связывать нить, чтобы просто повесить до этого времени.
Хотя ответ JonSkeet объясняет разницу в отличном для меня способе, самым большим практическим отличием является обработка исключений .
Task.WaitAll
выдает Task.WaitAll
AggregateException
когда бросается какая-либо из задач, и вы можете проверить все заброшенные исключения. await Task.WhenAll
в 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(); } }
В качестве примера разницы – если у вас есть задача, что-то делает с streamом пользовательского интерфейса (например, задача, представляющая анимацию в раскадровке), если вы Task.WaitAll()
тогда stream пользовательского интерфейса блокируется и пользовательский интерфейс никогда не обновлено. если вы используете await Task.WhenAll()
тогда stream пользовательского интерфейса не блокируется, и пользовательский интерфейс будет обновлен.
Что они делают:
- Внутренне оба делают то же самое.
Какая разница:
- WaitAll – это блокирующий вызов
- Когда All – not – code будет продолжать выполнение
Используйте, когда:
- WaitAll, когда не может продолжаться без результата
- WhenAll, когда только что уведомляться, не блокируется