C# 韦塔尔对惠纳尔

C# 韦塔尔对惠纳尔,c#,asynchronous,async-await,task-parallel-library,C#,Asynchronous,Async Await,Task Parallel Library,异步CTP中的Task.WaitAll()和Task.WhenAll()之间有什么区别? 您能提供一些示例代码来说明不同的用例吗?任务。WaitAll将阻塞当前线程,直到所有任务都完成 Task.whalll返回一个任务,该任务表示等待一切完成的操作 这意味着,通过异步方法,您可以使用: await Task.WhenAll(tasks); 。。。这意味着当所有事情都完成后,您的方法将继续,但在此之前,您不会绑定一个线程来闲逛。作为一个不同的示例——如果您有一个任务,那么如果您task.Wai

异步CTP中的
Task.WaitAll()
Task.WhenAll()
之间有什么区别?
您能提供一些示例代码来说明不同的用例吗?

任务。WaitAll
将阻塞当前线程,直到所有任务都完成

Task.whalll
返回一个任务,该任务表示等待一切完成的操作

这意味着,通过异步方法,您可以使用:

await Task.WhenAll(tasks);

。。。这意味着当所有事情都完成后,您的方法将继续,但在此之前,您不会绑定一个线程来闲逛。

作为一个不同的示例——如果您有一个任务,那么如果您
task.WaitAll()
然后UI线程被阻止,UI永远不会更新。如果使用
wait Task.WhenAll()
,则UI线程不会被阻止,UI将被更新。

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

Task.WaitAll
在任何任务抛出时抛出一个
aggregateeexception
,您可以检查所有抛出的异常。
wait任务中的
wait
。当所有
打开
aggregateeexception
并仅“返回”第一个异常时

当下面的程序使用
wait Task.whalll(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.
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.
使用
Task.WaitAll(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.
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();
    }
}
他们做什么:

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

区别是什么:

  • WaitAll是一个阻塞呼叫
  • 当所有-不-代码将继续执行

在以下情况下使用:

  • WaitAll如果没有结果,则无法继续
  • 什么时候什么时候才通知,什么时候不封锁

经过大量阅读,很明显异步与线程无关@Vince:我认为“与线程无关”是言过其实了,理解异步操作如何与线程交互很重要。@KevinBui:不,它不应该阻止它-它将等待
返回的任务,“但这和阻止线程不一样。”JonSkeet也许这两者之间的精确区别对我来说太微妙了。你能给我(可能还有我们其他人)指一些能说明区别的参考资料吗?@CatShoes:不太可能,我已经解释得很清楚了。我想我可以打个比方——这就像点外卖,然后站在门口等外卖,与点外卖,做其他事情,然后在快递员到达时开门……最大的实际区别是异常处理。真正地因为这并不是最大的实际区别。最大的实际区别是一个是异步和非阻塞,而另一个是阻塞。这比它如何处理异常重要得多。感谢您指出这一点。这个解释在我目前正在工作的场景中很有用。也许不是“最大的实际差异”,但绝对是一个很好的调用;等待t2;等待t3vs
等待任务时(t1、t2、t3)
此异常行为是否与此处的文档相矛盾()“如果提供的任何任务在故障状态下完成,则返回的任务也将在故障状态下完成,其中其异常将包含来自每个提供任务的未包装异常集合。”我认为这是一个伪代码<等待> <代码>,而不是这两种方法的区别。两者都传播一个
聚合异常
,要么直接抛出,要么通过一个属性(属性)。@MartinRhodes但是如果你不立即等待它,而是继续其他工作,然后等待它呢?据我所知,
WaitAll
没有这种可能性。@Jeppe在您完成其他一些工作后,您是否可以更改对
Task.WaitAll
的调用?我的意思是,不要在开始任务后立即调用它。如果设置ConfigureAwait(false),可以避免这种情况;在等待的任务上。不过,我不推荐使用WaitAll