Search code examples
c#restasynchronousapi-design

Will making a controller method async improve its performance? What is the benefit?


Disclaimer: I've considered thoroughly whether this question is opinion-based, because I understand the importance of following the site's rules. My conclusion is that it's sufficiently specific to be answered here. My deepest apologies if I'll stand corrected.

I chose to write my controller without async and Task. The way I figured, there was nothing to gain in asynchronizing the operation because of two reasons.

  1. The whole view model is served at once and there's no meaningful information to present until the whole content is ready to be rendered (i.e. no list being gradually transferred).

  2. The operations in the service need to do some heavy data massage and are based on logic that assumes knowledge of all retrieved elements and also stores certain info prior to exposing it (i.e. no SaveChangesAsync() or such is possible and using AsNoTracking() is present).

The class describing the view model looks roughly like so.

public class TheViewModel
{
  public string Name { get; set; }
  public byte[] Pieces { get; set; }
  public Guid Id { get; set; }
  public Dictionary<int, Info> { get; set; }
}

public class Info
{
  public Guid Id { get; set; }
  public Guid ParentLeftId { get; set; }
  public Guid ParentRightId { get; set; }
  public Guid ParentRandId { get; set; }
  public int[] Data { get; set; }
  public List<DateTime> { get; set; }
}

A colleague of mine batted the eye reacting to my choice and argued that:

a. it's not the recommended way, b. the operation will be performed less efficiently, c. it's against best practice.

We googled and read quite some blogs. The general impression tells that the argument is valid. However, I question its relevance in our case. Prestanda is not a democratic issue and can't be opinion-based.

When I tried to look up actual references (MSDN, SO etc.) where it's stated how exactly the performance would be affected, I got very little. I haven't found much info on how to reliably test it, neither.


Solution

  • I'll try explaining this in a different way.

    Async/await generally helps with IO operations. Those include (but are not limited to): accessing files, accessing a DB, making a call to a webservice, doing something with network sockets, or even accessing some special hardware like a scanner. Basically there are points in time when your code needs to wait for the result of some external operation - a file read operation, an SQL query, a HTTP request, whatever.

    And this is what async/await helps with. Without it, your thread would be stuck waiting for the results, which usually takes a loooong time. But with it, your thread can switch to doing something else while it's waiting. Thus, your CPU can be used more efficiently.

    Note - this isn't multithreading. There is no additional thread that "actually does the work". Instead, deep down underneath all the layers of abstraction, the computer is waiting for some piece of hardware to report back - a hard drive, a network adapter, whatever. (Well, yes, you can also wait for another thread to finish doing whatever it's doing, but that's a rather uncommon scenario)

    In your scenario, using async/await you could serve two incoming REST requests with a single thread. You'd start on the first one, then it would get to a point where it needs to wait (say, because it was executing an SQL query), and ASP.NET would switch over to doing the second one. Then when the second one gets to wait (or maybe completes), ASP.NET would check back if the SQL results are in and it can continue with the first one. Your thread will never be processing more than one request at the same time, but it will switch back and forth among them - whenever one gets to wait, it'll continue another. Thus you get efficiency.

    Mind you, if your requests spend more time calculating something on the CPU than they spend waiting for some external IO, your gains from async/await will be smaller. And if you do no IO at all (like your results are dependent only on the request contents), then you indeed don't need any async/await because there's nothing to await.

    Even if you do find use for async/await, it won't help any single request process faster - it'll just allow you to process more requests at the same time.