在性能方面,这两种方法会并行运行 GetAllWidgets()
和 GetAllFoos()
吗?
有什么理由使用其中一个吗?编译器在幕后似乎发生了很多事情,所以我不清楚。
============= 方法A:使用多个等待======================
public async Task<IHttpActionResult> MethodA()
{
var customer = new Customer();
customer.Widgets = await _widgetService.GetAllWidgets();
customer.Foos = await _fooService.GetAllFoos();
return Ok(customer);
}
=============== MethodB:使用Task.WaitAll =====================
public async Task<IHttpActionResult> MethodB()
{
var customer = new Customer();
var getAllWidgetsTask = _widgetService.GetAllWidgets();
var getAllFoosTask = _fooService.GetAllFos();
Task.WaitAll(new List[] {getAllWidgetsTask, getAllFoosTask});
customer.Widgets = getAllWidgetsTask.Result;
customer.Foos = getAllFoosTask.Result;
return Ok(customer);
}
======================================
_widgetService.GetAllWidgets()
完成时执行 _fooService.GetAllFoos()
,methodB 将在来自 _fooService.GetAllFoos()
的未完成任务返回时执行它。
第一个选项不会同时执行这两个操作。它将执行第一个并等待其完成,然后才执行第二个。
第二个选项将同时执行,但将同步等待它们(即在阻塞线程时)。
您不应该同时使用这两个选项,因为第一个比第二个完成得慢,而第二个在不需要的情况下阻塞线程。
您应该使用 Task.WhenAll
异步等待这两个操作:
public async Task<IHttpActionResult> MethodB()
{
var customer = new Customer();
var getAllWidgetsTask = _widgetService.GetAllWidgets();
var getAllFoosTask = _fooService.GetAllFos();
await Task.WhenAll(getAllWidgetsTask, getAllFoosTask);
customer.Widgets = await getAllWidgetsTask;
customer.Foos = await getAllFoosTask;
return Ok(customer);
}
请注意,在 Task.WhenAll
完成后,两个任务都已完成,因此等待它们立即完成。
简短的回答:没有。
Task.WaitAll
是阻塞的,await
一遇到任务就返回,并注册函数的剩余部分和延续。
您正在寻找的“批量”等待方法是 Task.WhenAll
,它实际上创建了一个新的 Task
,它会在所有交给该函数的任务完成后完成。
像这样:await Task.WhenAll({getAllWidgetsTask, getAllFoosTask});
那是为了阻塞问题。
此外,您的第一个函数不会并行执行这两个函数。要使其与 await
一起使用,您必须编写如下内容:
var widgetsTask = _widgetService.GetAllWidgets();
var foosTask = _fooService.GetAllWidgets();
customer.Widgets = await widgetsTask;
customer.Foos = await foosTask;
这将使第一个示例的行为与 Task.WhenAll
方法非常相似。
只有您的第二个选项将并行运行它们。您的第一个将按顺序等待每个呼叫。
一旦您调用异步方法,它将开始执行。无法确定它是在当前线程上执行(因此同步运行)还是异步运行。
因此,在您的第一个示例中,第一个方法将开始工作,但随后您使用 await 人为地停止了代码流。因此,在第一个方法完成执行之前,不会调用第二个方法。
第二个示例调用这两种方法,而不用等待来停止流。因此,如果方法是异步的,它们可能会并行运行。
作为@i3arnon 所说的补充。您会看到,当您使用 await
时,您必须将封闭方法声明为 async
,但使用 waitAll
您不需要。这应该告诉您,它比主要答案所说的要多。这里是:
WaitAll
将阻塞直到给定任务完成,当这些任务正在运行时,它不会将控制权交还给调用者。同样如前所述,任务与它们自己异步运行,而不是与调用者异步运行。
Await
不会阻塞调用者线程,但它会暂停其下方代码的执行,但在任务运行时,控制权会返回给调用者。对于将控制权返回给调用者(被调用的方法正在运行异步)这一事实,您必须将该方法标记为异步。
希望区别很明显。干杯
不定期副业成功案例分享
await Task.WhenAll(getAllWidgetsTask, getAllFoosTask);
并等待任务(在等待第一个任务之前启动第二个任务)。Result
将所有异常包装在AggregateException
中,然后您需要在所有错误处理代码中解包。await
为您解开它。除此之外,它们是相同的。