【发布时间】:2011-09-01 16:16:18
【问题描述】:
异步 CTP 中的 Task.WaitAll() 和 Task.WhenAll() 有什么区别?
您能否提供一些示例代码来说明不同的用例?
【问题讨论】:
标签: c# asynchronous async-await task-parallel-library
异步 CTP 中的 Task.WaitAll() 和 Task.WhenAll() 有什么区别?
您能否提供一些示例代码来说明不同的用例?
【问题讨论】:
标签: c# asynchronous async-await task-parallel-library
虽然 JonSkeet 的回答以一种典型的出色方式解释了差异,但还有另一个差异:异常处理。
Task.WaitAll 在任何任务抛出时抛出 AggregateException,您可以检查所有抛出的异常。 await Task.WhenAll 中的 await 解开 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;与await Task.WhenAll(t1,t2,t3);之间的比较
await 的产物,这两种方法之间没有区别。两者都传播AggregateException,要么直接抛出,要么通过属性(Task.Exception 属性)。
他们做什么:
有什么区别:
在什么时候使用:
【讨论】:
WaitAll 没有这种可能性。
Task.WaitAll的调用吗?我的意思是,不要在开始任务后立即调用它。
Task.WaitAll 阻塞当前线程,直到一切都完成。
Task.WhenAll 返回一个task,表示等待一切完成的动作。
这意味着从异步方法中,您可以使用:
await Task.WhenAll(tasks);
...这意味着您的方法将在一切完成后继续执行,但您不会占用一个线程来闲逛直到那个时候。
【讨论】:
WhenAll返回的任务,但这不一样作为阻塞线程。
作为差异的一个例子——如果你有一个任务与 UI 线程做一些事情(例如一个代表故事板中动画的任务)如果你 Task.WaitAll() 那么 UI 线程被阻塞并且 UI 是从未更新。如果你使用await Task.WhenAll(),那么UI线程不会被阻塞,UI会被更新。
【讨论】: