TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.77K subscribers
Post #1215 1.48K
День девятьсот девяносто первый. #ЗаметкиНаПолях #AsyncTips
Ожидание завершения группы задач

Задача:
есть несколько задач, и нужно подождать, пока они все завершатся.

Решение
Для этой цели существует метод Task.WhenAll. Он получает несколько задач и возвращает задачу, которая завершается при завершении всех указанных задач.
Task task1 = Task.Delay(100);
Task task2 = Task.Delay(200);
Task task3 = Task.Delay(150);
await Task.WhenAll(task1, task2, task3);

Если все задачи имеют одинаковый тип результата и все завершаются успешно, то задача Task.WhenAll возвращает массив, содержащий результаты всех задач:
Task<int> task1 = Task.FromResult(3);
Task<int> task2 = Task.FromResult(5);
Task<int> task3 = Task.FromResult(7);
int[] results = await Task.WhenAll(task1, task2, task3);
// "results" содержит { 3, 5, 7 }

Есть перегруженная версия Task.WhenAll, которая получает IEnumerable с задачами. Тем не менее заметьте, что при использовании LINQ код получается более понятным, когда последовательность явно материализуется:
async Task<string> GetAllAsync(
HttpClient client,
IEnumerable<string> urls)
{
// Определяем действие для каждого URL
var downloads = urls.Select(url => client.GetStringAsync(url));

// Задачи ещё не запущены, т.к.
// последовательность не материализована

// Запускаем загрузку для всех URL одновременно
Task<string>[] downloadTasks = downloads.ToArray();

// Все задачи запущены.
// Асинхронно ожидаем завершения всех загрузок
string[] htmlPages =
await Task.WhenAll(downloadTasks);

return string.Concat(htmlPages);
}

Если одна из задач выбросит исключение, то Task.WhenAll вернёт задачу в статусе Faulted с этим исключением. Если сразу несколько задач выдают исключения, то все они помещаются в задачу, возвращаемую Task.WhenAll. При ожидании этой задачи будет выдано только одно из них:
try
{
await Task.WhenAll(task1, task2);
}
catch (Exception ex)
{
// "ex" – исключение либо из task1, либо из task2
...
}

Обычно первого «попавшегося» исключения достаточно, но, если вам нужны все исключения, проверьте свойство Exception задачи, возвращаемой Task.WhenAll:
Task allTasks = Task.WhenAll(task1, task2);
try
{
await Task.WhenAll(allTasks);
}
catch
{
AggregateException allExceptions = allTasks.Exception;
...
}

Если ни одна задача не выбросила исключения, но хотя бы одна задача была отменена, то задача, возвращённая Task.WhenAll, будет в статусе Canceled.

Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 2.
  • 👍 1
More from @netdeveloperdiary
  1. Oct 10, 2026День 2810. #ЧтоНовенького #VSCode Более Быстрый и Лёгкий C# Dev Kit Мы, разработчики, люби…
  2. Oct 9, 2026День 2809. #Карьера 5 Навыков, Которые Помогут Быстрее Стать Сеньором. Окончание Начало 3.…
  3. Oct 8, 2026День 2808. #Карьера 5 Навыков, Которые Помогут Быстрее Стать Сеньором. Начало В ИТ есть се…
  4. Oct 7, 2026День 2807. #ЗаметкиНаПолях Типы Коллекций в .NET, Которые Стоит Попробовать. Окончание Нач…
  5. Oct 6, 2026🦈 Открытое собеседование на Middle C# | 6 октября, 19:00 МСК Приглашаем на открытое собес…
  6. Oct 6, 2026День 2806. #ЗаметкиНаПолях Типы Коллекций в .NET, Которые Стоит Попробовать. Начало Больши…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →