436

Task.WaitAll()Async CTP和Async CTP有什么区别Task.WhenAll()?您能否提供一些示例代码来说明不同的用例?

4

4 回答 4

638

Task.WaitAll阻塞当前线程,直到一切都完成。

Task.WhenAll返回一个任务,该任务表示等待一切完成的动作。

这意味着从异步方法中,您可以使用:

await Task.WhenAll(tasks);

...这意味着当一切都完成后,您的方法将继续,但您不会占用线程来闲逛直到那个时候。

于 2011-05-25T11:03:52.617 回答
96

虽然 JonSkeet 的回答以一种典型的出色方式解释了差异,但还有另一个区别:异常处理

Task.WaitAll当任何任务抛出时抛出一个AggregateException,您可以检查所有抛出的异常。awaitinawait 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();
    }
}
于 2016-11-19T00:25:56.807 回答
33

举个不同的例子——如果你有一个任务用 UI 线程做一些事情(例如,一个代表 Storyboard 中动画的任务),Task.WaitAll()那么 UI 线程被阻塞并且 UI 永远不会更新。如果你使用await Task.WhenAll(),那么 UI 线程不会被阻塞,并且 UI 将被更新。

于 2016-04-13T03:24:54.137 回答
18

他们在做什么:

  • 在内部,两者都做同样的事情。

有什么不同:

  • WaitAll是一个阻塞调用
  • WhenAll - not - 代码将继续执行

在以下情况下使用 which:

  • WaitAll在没有结果的情况下无法继续
  • WhenAll什么时候只通知什么,而不是阻塞
于 2018-08-23T13:54:38.863 回答