Відповіді:
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
після того, як зробили якусь іншу роботу? Я маю на увазі, замість того, щоб викликати це відразу після початку своїх завдань.