Відповіді:
Task.WaitAll блокує поточну нитку, поки все не завершиться.
Task.WhenAllповертає завдання, яке представляє дію очікування, поки все не завершиться.
Це означає, що з методу асинхронізації можна використовувати:
await Task.WhenAll(tasks);
... це означає, що ваш метод продовжиться, коли все буде завершено, але ви не зв’яжете нитку, щоб просто зависати до цього часу.
WhenAll, але це не те саме, що блокувати нитку.
Хоча відповідь JonSkeet пояснює різницю типово відмінним способом, є ще одна відмінність: обробка виключень .
Task.WaitAllкидає AggregateExceptionколи будь-яке завдання кидає, і ви можете вивчити всі викинуті винятки. awaitУ 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;vsawait Task.WhenAll(t1,t2,t3);
await, а не різницею між двома методами. Обидва розповсюджують AggregateException, або кидаючи безпосередньо, або через майно ( Task.Exceptionвластивість).
Як приклад різниці - якщо у вас є завдання, робиться щось з потоком інтерфейсу (наприклад, завдання, яке представляє анімацію на дошці розкадрування), якщо ви Task.WaitAll()потоку користувальницького інтерфейсу заблоковані і користувальницький інтерфейс ніколи не оновлюється. якщо ви використовуєте, await Task.WhenAll()то потік інтерфейсу не блокується, і інтерфейс буде оновлений.
Що вони роблять:
Яка різниця:
Використовуйте, коли:
WaitAllяк я це розумію.
Task.WaitAll після того, як зробили якусь іншу роботу? Я маю на увазі, замість того, щоб викликати це відразу після початку своїх завдань.