Ответ
Task.WaitAll и Task.WhenAll служат для ожидания завершения группы задач, но делают это принципиально разными способами, что влияет на поток выполнения и производительность.
Task.WaitAll(params Task[] tasks) — это синхронный блокирующий метод.
- Вызывает блокировку текущего потока до тех пор, пока все переданные задачи не будут завершены (успешно, с ошибкой или отменой).
- Вызов на UI-потоке приведет к зависанию интерфейса.
- Не рекомендуется использовать в асинхронном коде (помеченном
async), так как он блокирует поток.
Task.WhenAll(params Task[] tasks) — это асинхронный неблокирующий метод.
- Возвращает новую задачу (
Task), которая будет завершена, когда завершатся все исходные задачи. - Не блокирует текущий поток. Поток освобождается, пока задачи выполняются.
- Предназначен для использования с оператором
awaitвнутри асинхронных методов.
Сравнение на практике:
public async Task ProcessDataAsync()
{
Task<int> downloadTask = DownloadFileAsync();
Task<string> apiTask = CallApiAsync();
Task<bool> dbTask = UpdateDatabaseAsync();
// ПЛОХО: Синхронная блокировка. Поток будет простаивать в ожидании.
// Task.WaitAll(downloadTask, apiTask, dbTask);
// ХОРОШО: Асинхронное ожидание. Поток освобождается для другой работы.
await Task.WhenAll(downloadTask, apiTask, dbTask);
// После WhenAll все задачи гарантированно завершены.
int fileSize = downloadTask.Result;
string response = apiTask.Result;
bool success = dbTask.Result;
}
// Task.WhenAll также удобен для агрегации результатов.
public async Task<int[]> GetMultipleValuesAsync()
{
Task<int> task1 = GetValueAsync(1);
Task<int> task2 = GetValueAsync(2);
Task<int> task3 = GetValueAsync(3);
// Ожидаем завершения всех и сразу получаем массив результатов.
int[] results = await Task.WhenAll(task1, task2, task3);
return results; // [значение1, значение2, значение3]
}
Вывод: В современном асинхронном коде почти всегда следует использовать await Task.WhenAll(...). Task.WaitAll может быть оправдан только в контексте синхронного кода, например, в методе Main консольного приложения.
Ответ 18+ 🔞
Так, слушай, про эти ваши Task.WaitAll и Task.WhenAll — это ж классика, два способа наступить на одни и те же грабли, но с разным звуком.
Представь, что задачи — это твои кореша, которых ты послал за пивом. Task.WaitAll — это ты стоишь посреди коридора, упершись лбом в стену, и тупо ждешь, пока они все вернутся. Ни телевизор посмотреть, ни чипсы открыть — просто стоишь, блядь, как истукан, и поток твой намертво заблокирован. Вызови эту штуку в UI — и всё, интерфейс повиснет, пользователь будет материться, а ты будешь смотреть в пустой экран, как дурак.
А вот Task.WhenAll — это умный подход. Ты говоришь: «Ребята, как все будете с пивом — свистните». И сам идешь на диван, включаешь футбол, закусываешь чем есть. Поток-то твой освобождается! А когда все задачи доложат о выполнении, тебе просто прилетит уведомление. В коде это через await делается — красиво, асинхронно, без тормозов.
Смотри, как это в деле выглядит:
public async Task ProcessDataAsync()
{
Task<int> downloadTask = DownloadFileAsync();
Task<string> apiTask = CallApiAsync();
Task<bool> dbTask = UpdateDatabaseAsync();
// ТУПИКОВЫЙ ПУТЬ: Весь поток встанет колом.
// Task.WaitAll(downloadTask, apiTask, dbTask);
// ПУТЬ РАЗУМА: Ждем, не блокируя ничего.
await Task.WhenAll(downloadTask, apiTask, dbTask);
// Все уже готово, можно результаты забирать.
int fileSize = downloadTask.Result;
string response = apiTask.Result;
bool success = dbTask.Result;
}
А ещё WhenAll — он ж не только ждет, он может результаты все разом собрать, красота:
public async Task<int[]> GetMultipleValuesAsync()
{
Task<int> task1 = GetValueAsync(1);
Task<int> task2 = GetValueAsync(2);
Task<int> task3 = GetValueAsync(3);
// Ждем всех и сразу получаем массив, без возни с каждым Result.
int[] results = await Task.WhenAll(task1, task2, task3);
return results; // [значение1, значение2, значение3]
}
Так что правило простое, ёпта: пишешь async метод — хочешь ждать несколько задач — берешь await Task.WhenAll(...) и спишь спокойно. Task.WaitAll оставь для каких-нибудь легаси-консольных приложений, где потоковому параличу всё равно не на кого влиять. Всё, вопрос закрыт.