多个等待与任务。等待全等效?

在性能方面,这两个方法是否会并行运行 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: 使用任务 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);
}

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

37257 次浏览

Only your second option will run them in parallel. Your first will wait on each call in sequence.

As soon as you invoke the async method it will start executing. Whether it will execute on the current thread (and thus run synchronously) or it will run async is not possible to determine.

Thus, in your first example the first method will start doing work, but then you artificially stops the flow of the code with the await. And thus the second method will not be invoked before the first is done executing.

The second example invokes both methods without stopping the flow with an await. Thus they will potentially run in parallel if the methods are asynchronous.

The first option will not execute the two operations concurrently. It will execute the first and await its completion, and only then the second.

The second option will execute both concurrently but will wait for them synchronously (i.e. while blocking a thread).

You shouldn't use both options since the first completes slower than the second and the second blocks a thread without need.

You should wait for both operations asynchronously with 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);
}

Note that after Task.WhenAll completed both tasks already completed so awaiting them completes immediately.

Short answer: No.

Task.WaitAll is blocking, await returns the task as soon as it is encountered and registers the remaining part of the function and continuation.

The "bulk" waiting method you were looking for is Task.WhenAll that actually creates a new Task that finishes when all tasks that were handed to the function are done.

Like so: await Task.WhenAll({getAllWidgetsTask, getAllFoosTask});

That is for the blocking matter.

Also your first function does not execute both functions parallel. To get this working with await you'd have to write something like this:

var widgetsTask = _widgetService.GetAllWidgets();
var foosTask = _fooService.GetAllWidgets();
customer.Widgets = await widgetsTask;
customer.Foos = await foosTask;

This will make the first example to act very similar to the Task.WhenAll method.

As an addition to what @i3arnon said. You will see that when you use await you are forced to have to declare the enclosing method as async, but with waitAll you don't. That should tell you that there is more to it than what the main answer says. Here it is:

WaitAll will block until the given tasks finish, it does not pass control back to the caller while those tasks are running. Also as mentioned, the tasks are run asynchronous to themselves, not to the caller.

Await will not block the caller thread, it will however suspend the execution of the code below it, but while the task is running, control is returned back to the caller. For the fact that control is returned back to the caller (the called method is running async), you have to mark the method as async.

Hopefully the difference is clear. Cheers