Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple Await Async in .Net WebApi

We have a number of async controllers and services that make use of the await/async keywords.

A number of the actions look a little like:

public async Task<SomeViewModel> Get(int id)
{
    var someData = await _service.GetData(id);
    var someOtherData = await _service.GetMoreData(id);
    return new SomeViewModel
    {
        Data = someData,
        OtherData = someOtherData,
    }
}

It might be that the service calls themselves also have multuple awaits. The await will typically be against an async call to entity framework, a service bus or a 3rd party web endpoint.

One of my colleagues came to be today suggesting that this kind of code was pointless, that it would simply generate extra work for thread management and the under load we would be actually generate more work for the for the runtime and slow the app down as a result.

Are they right and if so what is considered best practise for async / await when you have multiple IO bound calls in a Web API request?

like image 501
ilivewithian Avatar asked Apr 02 '14 14:04

ilivewithian


2 Answers

One of my colleagues came to be today suggesting that this kind of code was pointless, that it would simply generate extra work for thread management and the under load we would be actually generate more work for the for the runtime and slow the app down as a result.

That's amusing, since the opposite is actually true. As other answerers have pointed out, if you're using true asynchronous operations (i.e., not Task.Run or anything like that), then there are fewer threads used and the application responds better under load.

Some folks (not me) have done studies on "average" ASP.NET applications transitioning to async, and they have found a 10x to 100x scalability increase when moving to async as opposed to blocking calls. You can expect better scalability if your application has more asynchronous work to do.

If you look at a single request, and if each operation is done one at a time, then the asynchronous version is slightly slower. But if you consider the system as a whole - especially under load - the asynchronous version scales better. Another aspect of asynchronous handlers that is often overlooked is that the asynchronous version responds faster to sudden loads than the thread pool can by itself.

Also, asynchronous code makes it easy to execute concurrent requests, which can make the individual requests faster as well:

public async Task<SomeViewModel> Get(int id)
{
  var someDataTask = _service.GetData(id);
  var someOtherDataTask = _service.GetMoreData(id);
  await Task.WhenAll(someDataTask, someOtherDataTask);
  return new SomeViewModel
  {
    Data = await someDataTask,
    OtherData = await someOtherDataTask,
  }
}
like image 183
Stephen Cleary Avatar answered Sep 28 '22 05:09

Stephen Cleary


If you are serving only a single request at a time in your app pool, a blocking solution will be more efficient.

If you have just about any parallelism at all, async/await will probably be more efficient because it results in less threads, and less context switching. Because of this, I/O-bound workloads (where context switching is highly likely if you block) are actually one of the places where async/await shines the best.

As answered by boklucius, async I/O in .NET targets I/O Completion Ports under the covers, which uses a thread pool not to block on I/O but to process I/O completions. Using async will definitely not bloat your thread count.

like image 31
Cory Nelson Avatar answered Sep 28 '22 05:09

Cory Nelson