多个等待 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是阻塞的,awaitreturns任务一遇到就注册剩下的部分函数并继续。

您正在寻找的 "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),你必须将方法标记为异步。

希望区别很明显。干杯