Ответ
Для ожидания завершения группы задач используйте статические методы Task.WaitAll (блокирующий) или Task.WhenAll (асинхронный).
1. Task.WaitAll(Task[]) — синхронное (блокирующее) ожидание.
Останавливает текущий поток до завершения всех задач. Используйте в синхронном коде, но избегайте в UI-потоках или асинхронных методах, чтобы не вызывать deadlock.
Task[] tasks = new Task[3];
tasks[0] = Task.Run(() => DoWork(1));
tasks[1] = Task.Run(() => DoWork(2));
tasks[2] = Task.Run(() => DoWork(3));
// Текущий поток блокируется здесь
Task.WaitAll(tasks);
Console.WriteLine("Все задачи завершены.");
2. await Task.WhenAll(Task[]) — асинхронное ожидание.
Предпочтительный способ в асинхронных методах (async). Не блокирует поток, а освобождает его для других операций.
public async Task ProcessAllDataAsync()
{
Task<int>[] downloadTasks = new Task<int>[5];
for (int i = 0; i < downloadTasks.Length; i++)
{
downloadTasks[i] = DownloadDataAsync(i);
}
// Ожидаем завершения всех задач, не блокируя поток
int[] results = await Task.WhenAll(downloadTasks);
// Когда все задачи завершены, работаем с результатами
int sum = results.Sum();
Console.WriteLine($"Общая сумма: {sum}");
}
Критически важная деталь: Обработка исключений.
Task.WaitAllиawait Task.WhenAllпри ошибке в любой из задач выбрасываютAggregateException(в .NET Core 3.0+WaitAllможет выбросить первое исключение).- Правильный подход — проверять статус каждой задачи:
try { await Task.WhenAll(tasks); } catch // Ловим первое исключение, но AggregateException могло быть "развернуто" { // Игнорируем здесь, проверяем задачи ниже }
// Анализируем каждую задачу на наличие ошибок foreach (var task in tasks) { if (task.IsFaulted) { // task.Exception - это AggregateException, содержащее реальные ошибки Console.WriteLine($"Задача завершилась с ошибкой: {task.Exception?.InnerException?.Message}"); } }
Используйте `WhenAll` для асинхронного кода и всегда планируйте обработку частичных сбоев. Ответ 18+ 🔞
Смотри, есть два главных способа дождаться, пока куча твоих тасков сделают свои дела. Как будто ты отправил кучу курьеров и ждёшь, пока все вернутся, чтобы посчитать бабки.
Первый — Task.WaitAll(Task[]). Это как посадить себя на цепь.
Пока все задачи не приползут, твой текущий поток встанет как вкопанный. Никуда не денется. Используй это в синхронном коде, но, блядь, ни в коем случае не лезь с этим в UI-поток или в async метод — там тебя просто заблокирует насмерть, и будет тебе вечный deadlock, ёпта.
Task[] tasks = new Task[3];
tasks[0] = Task.Run(() => DoWork(1));
tasks[1] = Task.Run(() => DoWork(2));
tasks[2] = Task.Run(() => DoWork(3));
// Всё, тут поток упрётся лбом в стенку и будет ждать
Task.WaitAll(tasks);
Console.WriteLine("Все задачи завершены.");
Второй — await Task.WhenAll(Task[]). Это по-умному.
Вот это уже красота. Кинул задачи, сказал "ждитесь", а сам поток освободил — пусть другие дела делает. Используется внутри async методов.
public async Task ProcessAllDataAsync()
{
Task<int>[] downloadTasks = new Task<int>[5];
for (int i = 0; i < downloadTasks.Length; i++)
{
downloadTasks[i] = DownloadDataAsync(i);
}
// Спокойно ждём, не блокируя весь мир вокруг
int[] results = await Task.WhenAll(downloadTasks);
// Все приползли, можно результаты собирать
int sum = results.Sum();
Console.WriteLine($"Общая сумма: {sum}");
}
А теперь, сука, самое важное — исключения.
И WaitAll, и WhenAll при первой же ошибке в любой задаче выкинут тебе исключение. Но проблема в том, что если одна задача наебнулась, а остальные норм, то тебе надо понять, кто именно сломался и почему.
- Просто поймать
try/catch— это полдела. Там тебе, возможно, прилетитAggregateException(или в новых .NET Core его могут развернуть). - Правильный, полный подход — проверить каждую задачу по отдельности, как подозреваемого:
try
{
await Task.WhenAll(tasks);
}
catch // Ловим что прилетело, но это может быть только первая ошибка
{
// А нам похуй на этот catch сейчас, мы пойдём ниже смотреть каждую задачу
}
// Вот теперь идём и выясняем, кто тут у нас мудак
foreach (var task in tasks)
{
if (task.IsFaulted) // Эта задача накосячила
{
// Залезаем в task.Exception (это опять AggregateException) и смотрим корень зла
Console.WriteLine($"Задача обосралась: {task.Exception?.InnerException?.Message}");
}
}
Короче, запомни: для асинхронщины — WhenAll, и всегда проверяй задачи по одной на предмет косяков, потому что жизнь не идеальна и что-то всегда может пойти не так.