多个等待与Task.WaitAll - 等效?

时间:2015-08-20 13:24:41

标签: c# .net async-await task-parallel-library

就性能而言,这两种方法是并行运行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);
}

===============方法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);
}

=====================================

5 个答案:

答案 0 :(得分:77)

第一个选项不会同时执行这两个操作。它将执行第一个并等待其完成,然后才执行第二个。

第二个选项将同时执行,但会同步等待它们(即阻塞线程时)。

您不应该同时使用这两个选项,因为第一个完成的速度比第二个慢,第二个阻止了一个不需要的线程。

您应该与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完成两项任务已完成后等待它们立即完成。

答案 1 :(得分:13)

简短回答:不。

Task.WaitAll阻塞,await在遇到任务后立即返回任务,并注册函数的剩余部分并继续。

&#34; bulk&#34;你正在寻找的等待方法是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方法非常相似。

答案 2 :(得分:0)

只有你的第二个选项会同时运行它们。你的第一个将按顺序等待每个电话。

答案 3 :(得分:0)

一旦调用异步方法,它就会开始执行。它是否将在当前线程上执行(从而同步运行)或者它将运行异步无法确定。

因此,在您的第一个示例中,第一个方法将开始工作,但随后您使用await人为地停止代码流。因此,在第一个方法执行完毕之前,不会调用第二个方法。

第二个示例调用两个方法而不使用await停止流。因此,如果方法是异步的,它们将潜在并行运行。

答案 4 :(得分:0)

作为@ i3arnon所说的补充。您会看到,使用await时,您不得不将封闭方法声明为async,而使用waitAll时则不必。那应该告诉你,除了主要答案所说的以外,还有更多的东西。在这里:

WaitAll将阻塞,直到给定任务完成为止,在这些任务运行时,它不会将控制权传递回调用方。同样如前所述,任务是异步运行的,而不是调用方。

Await不会阻塞调用者线程,但是它将暂停执行其下的代码,但是在任务运行时,控制权将返回给调用者。对于将控制权返回给调用者的事实(被调用的方法正在异步运行),您必须将该方法标记为异步。

希望区别很明显。干杯