it-roy-ru.com

WaitAll vs WhenAll

В чем отличие Task.WaitAll() и Task.WhenAll() от Async CTP? Можете ли вы предоставить пример кода для иллюстрации различных вариантов использования?

278
Yaron Levi

Task.WaitAll блокирует текущий поток, пока все не завершится.

Task.WhenAll возвращает task, которое представляет действие ожидания, пока все не будет завершено.

Это означает, что из асинхронного метода вы можете использовать:

await Task.WhenAll(tasks);

... что означает, что ваш метод продолжится, когда все будет завершено, но вы не будете связывать поток, чтобы просто торчать до этого времени.

423
Jon Skeet

Хотя ответ 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();
    }
}
40
tymtam

В качестве примера различия - если у вас есть задача, она что-то делает с потоком пользовательского интерфейса (например, задача, которая представляет анимацию в раскадровке), если вы Task.WaitAll(), тогда поток пользовательского интерфейса блокируется, а пользовательский интерфейс никогда не обновляется. если вы используете await Task.WhenAll(), тогда поток пользовательского интерфейса не блокируется, и пользовательский интерфейс будет обновлен.

16
J. Long

Что они делают:

  • Внутренне оба делают одно и то же.

Какая разница:

  • WaitAll блокирующий вызов
  • WhenAll - нет - код продолжит выполняться

Используйте, когда:

  • WaitAll когда невозможно продолжить без результата
  • WhenAll когда о чем только нужно уведомить, а не заблокировать
3
i100