多个等待 vs Task.WaitAll - 等价?
multiple awaits vs Task.WaitAll - equivalent?
在性能方面,运行GetAllWidgets()
和GetAllFoos()
这2个方法会并行吗?
是否有理由使用一个而不是另一个?编译器的幕后似乎发生了很多事情,所以我不太清楚。
=============方法A:使用多个等待======================
public async Task<IHttpActionResult> MethodA()
{
var customer = new Customer();
customer.Widgets = await _widgetService.GetAllWidgets();
customer.Foos = await _fooService.GetAllFoos();
return Ok(customer);
}
===============方法B:使用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);
}
=====================================
只有您的第二个选项会 运行 它们并行。您的第一个将按顺序等待每个呼叫。
只要调用异步方法,它就会开始执行。它是在当前线程上执行(因此 运行 同步执行)还是 运行 异步无法确定。
因此,在您的第一个示例中,第一个方法将开始工作,但随后您使用 await 人为地停止了代码流。因此在第一个方法执行完成之前不会调用第二个方法。
第二个示例调用了这两种方法,而没有使用 await 停止流程。因此,如果方法是异步的,它们可能会 运行 并行。
第一个选项不会同时执行两个操作。它将执行第一个并等待其完成,然后才执行第二个。
第二个选项将同时执行,但会同步等待它们(即阻塞线程)。
你不应该同时使用这两个选项,因为第一个比第二个慢,第二个会在不需要的情况下阻塞线程。
您应该使用 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
returns任务一遇到就注册剩下的部分函数并继续。
您正在寻找的 "bulk" 等待方法是 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
方法非常相似。
作为@i3arnon 所说的补充。您会看到,当您使用 await
时,您被迫必须将封闭方法声明为 async
,但使用 waitAll
则不需要。那应该告诉您,除了主要答案所说的之外,还有更多内容。这是:
WaitAll
将阻塞直到给定任务完成,它不会在这些任务 运行ning 时将控制权交还给调用者。同样如前所述,任务 运行 与它们自己异步,而不是与调用者异步。
Await
不会阻塞调用者线程,但是它会暂停其下面代码的执行,但是当任务 运行ning 时,控制权会返回给调用者。因为控制返回给调用者(被调用的方法是 运行ning async),你必须将方法标记为异步。
希望区别很明显。干杯
在性能方面,运行GetAllWidgets()
和GetAllFoos()
这2个方法会并行吗?
是否有理由使用一个而不是另一个?编译器的幕后似乎发生了很多事情,所以我不太清楚。
=============方法A:使用多个等待======================
public async Task<IHttpActionResult> MethodA()
{
var customer = new Customer();
customer.Widgets = await _widgetService.GetAllWidgets();
customer.Foos = await _fooService.GetAllFoos();
return Ok(customer);
}
===============方法B:使用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);
}
=====================================
只有您的第二个选项会 运行 它们并行。您的第一个将按顺序等待每个呼叫。
只要调用异步方法,它就会开始执行。它是在当前线程上执行(因此 运行 同步执行)还是 运行 异步无法确定。
因此,在您的第一个示例中,第一个方法将开始工作,但随后您使用 await 人为地停止了代码流。因此在第一个方法执行完成之前不会调用第二个方法。
第二个示例调用了这两种方法,而没有使用 await 停止流程。因此,如果方法是异步的,它们可能会 运行 并行。
第一个选项不会同时执行两个操作。它将执行第一个并等待其完成,然后才执行第二个。
第二个选项将同时执行,但会同步等待它们(即阻塞线程)。
你不应该同时使用这两个选项,因为第一个比第二个慢,第二个会在不需要的情况下阻塞线程。
您应该使用 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
returns任务一遇到就注册剩下的部分函数并继续。
您正在寻找的 "bulk" 等待方法是 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
方法非常相似。
作为@i3arnon 所说的补充。您会看到,当您使用 await
时,您被迫必须将封闭方法声明为 async
,但使用 waitAll
则不需要。那应该告诉您,除了主要答案所说的之外,还有更多内容。这是:
WaitAll
将阻塞直到给定任务完成,它不会在这些任务 运行ning 时将控制权交还给调用者。同样如前所述,任务 运行 与它们自己异步,而不是与调用者异步。
Await
不会阻塞调用者线程,但是它会暂停其下面代码的执行,但是当任务 运行ning 时,控制权会返回给调用者。因为控制返回给调用者(被调用的方法是 运行ning async),你必须将方法标记为异步。
希望区别很明显。干杯