应该使用`await Task.WhenAll`而不是在Web API控制器中使用`Task.WaitAll`吗?

huangapple go评论59阅读模式
英文:

Should I be using await Task.WhenAll rather than Task.WaitAll in a Web API controller

问题

以下是翻译好的部分:

我有一个Web API控制器,它执行以下操作:

public async Task<Result> Post([FromBody] MyBody postBody)
{
    // 执行任务
    var doSomethingTask = DoSomethingMethod();
    var doSomethingTask2 = DoSomethingMethod2();
    tasks.Add(doSomethingTask);
    tasks.Add(doSomethingTask2);

    Task.WaitAll(tasks.ToArray()); // 问题出在这一行

    // 以这些任务的结果异步执行某些操作
    await DoSomethingAsyncWithResults(doSomethingTask.Result, doSomethingTask2.Result);
}

对于您上面的代码,您的问题是是否应该实际使用 await Task.WhenAll(tasks.ToArray());,以及如果这样做是否会带来任何好处。请注意,这是一个Web API控制器,没有与此应用程序相关的用户界面,只是从前端异步调用它。

在我的实际环境中,可能会有5个此类实例运行,为前端提供服务。锁定此方法是否会阻止其响应其他请求?

希望这对您有所帮助。

英文:

I have a Web API controller that does the following:

    public async Task&lt;Result&gt; Post([FromBody] MyBody postBody)
    {
        // fire tasks
        var doSomethingTask = DoSomethingMethod();
        var doSomethingTask2 = DoSomethingMethod2();
        tasks.Add(doSomethingTask);
        tasks.Add(doSomethingTask2);

        Task.WaitAll(tasks.ToArray()); //line in question

        //do something async with results of these tasks
        await DoSomethingAsyncWithResults(doSomethingTask.Result,doSomethingTask2.Result);
   }

Now my question is in the above code should I actually be using

await Task.WhenAll(tasks.ToArray());

and what benefit - if any - would I see if I did that? Baring in mind this is a Web API controller so there is no UI to this application it's just getting called asynchronously from the frontend.

In my live environment there could be maybe 5 instances of this running, serving the front end. would locking up this method prevent it from responding to other requests?

答案1

得分: 0

你的Web服务器将使用更少的线程来处理更多的请求。好处在于可扩展性。另一个好处是代码一致性;该方法已经是async的,所以在有一个可以await的替代方案的情况下,将async方法同步阻塞是非常奇怪的。

锁定此方法会阻止它响应其他请求吗?

不会;ASP.NET默认是多线程的。不同之处在于在多等待期间,您是希望使用N个线程还是0个线程。请参阅我在ASP.NET上的文章Introduction to async/await on ASP.NET中关于同步与异步请求处理的部分。

英文:

> what benefit - if any - would I see if I did that? Baring in mind this is a Web API controller so there is no UI to this application it's just getting called asynchronously from the frontend.

Your web server would use fewer threads to serve more requests. The benefit is scalability. A secondary benefit would be code consistency; the method is already async, so it's very weird to have the async method synchronously block when there is an awaitable alternative right there.

> would locking up this method prevent it from responding to other requests?

No; ASP.NET is multithreaded by default. The difference is whether you want to use N threads or 0 threads during that multi-wait. See Synchronous vs Asynchronous Request Handling in my article Introduction to async/await on ASP.NET.

答案2

得分: -2

.WaitAll()阻塞调用线程,直到所有任务都完成。

.WhenAll()是一种将一组任务包装在单一Task对象中的方法。因此,您可以使用.Wait()await来等待它们。但是,它不仅仅局限于等待动作,如果您认为它应该执行其他操作,它可以做更多。它表示一个任务,当它的所有组成任务完成时,将继续执行下一个部分。这个版本不会阻塞调用线程。

另一个关键区别是异常处理。.WaitAll()将抛出一个包含所有故障任务内部抛出异常的AggregateException。而.WhenAll()会自行展开AggregateException,并且只返回第一个异常。

针对更新后的代码片段的更新:
在这里,在继续执行方法的最后一行之前,您绝对需要返回,所以.WaitAll()await在这里都是有效的,因为本质上您正在做相同的事情。如果您需要在以后的重构中链接更多任务或逻辑,那么最好使用await版本,因为这样需要稍微少些重写。

Task batch = Task.WhenAll(tasks.ToArray());
// 在以后的重构中链接更多任务或逻辑

var batchResults = await batch;
英文:

.WaitAll() will block the calling thread and literally wait until everything is complete

.WhenAll() is like a way of wrapping a group of tasks in a singular Task object. As a result you can .Wait() or await them if you want. But there is more you can do, it is not bound by this waiting action if you deem it should do something else. It simply represents a Task that will move on to the next part to execute when all of its composed tasks complete. This version will not block the calling thread

Another key difference is exception handling. .WaitAll() will throw an AggregateException that contains all of the inner throws from faulted Tasks. .WhenAll() instead unwraps the AggregateException on its own and returns only the first exception

Update in response to updated code snippet:
You absolutely need the return before moving on to execute the final line of the method here, so both .WaitAll() and await are valid here because in essence you are doing the same thing. If you need the ability to chain more tasks or logic onto it with later refactoring, then prefer to use the await version as it would be a little bit less re-writing

Task batch = Task.WhenAll(tasks.ToArray());
//chain on more things later
        
var batchResults = await batch;

huangapple
  • 本文由 发表于 2023年3月10日 01:50:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/75688310.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定