When should I use Async Controllers in ASP.NET MVC?

127,066

Solution 1

Asynchronous action methods are useful when an action must perform several independent long running operations.

A typical use for the AsyncController class is long-running Web service calls.

Should my database calls be asynchronous ?

The IIS thread pool can often handle many more simultaneous blocking requests than a database server. If the database is the bottleneck, asynchronous calls will not speed up the database response. Without a throttling mechanism, efficiently dispatching more work to an overwhelmed database server by using asynchronous calls merely shifts more of the burden to the database. If your DB is the bottleneck, asynchronous calls won’t be the magic bullet.

You should have a look at 1 and 2 references

Derived from @PanagiotisKanavos comments:

Moreover, async doesn't mean parallel. Asynchronous execution frees a valuable threadpool thread from blocking for an external resource, for no complexity or performance cost. This means the same IIS machine can handle more concurrent requests, not that it will run faster.

You should also consider that blocking calls start with a CPU-intensive spinwait. During stress times, blocking calls will result in escalating delays and app pool recycling. Asynchronous calls simply avoid this

Solution 2

You may find my MSDN article on the subject helpful; I took a lot of space in that article describing when you should use async on ASP.NET, not just how to use async on ASP.NET.

I have some concerns using async actions in ASP.NET MVC. When it improves performance of my apps, and when - not.

First, understand that async/await is all about freeing up threads. On GUI applications, it's mainly about freeing up the GUI thread so the user experience is better. On server applications (including ASP.NET MVC), it's mainly about freeing up the request thread so the server can scale.

In particular, it won't:

  • Make your individual requests complete faster. In fact, they will complete (just a teensy bit) slower.
  • Return to the caller/browser when you hit an await. await only "yields" to the ASP.NET thread pool, not to the browser.

First question is - is it good to use async action everywhere in ASP.NET MVC?

I'd say it's good to use it everywhere you're doing I/O. It may not necessarily be beneficial, though (see below).

However, it's bad to use it for CPU-bound methods. Sometimes devs think they can get the benefits of async by just calling Task.Run in their controllers, and this is a horrible idea. Because that code ends up freeing up the request thread by taking up another thread, so there's no benefit at all (and in fact, they're taking the penalty of extra thread switches)!

Shall I use async/await keywords when I want to query database (via EF/NHibernate/other ORM)?

You could use whatever awaitable methods you have available. Right now most of the major players support async, but there are a few that don't. If your ORM doesn't support async, then don't try to wrap it in Task.Run or anything like that (see above).

Note that I said "you could use". If you're talking about ASP.NET MVC with a single database backend, then you're (almost certainly) not going to get any scalability benefit from async. This is because IIS can handle far more concurrent requests than a single instance of SQL server (or other classic RDBMS). However, if your backend is more modern - a SQL server cluster, Azure SQL, NoSQL, etc - and your backend can scale, and your scalability bottleneck is IIS, then you can get a scalability benefit from async.

Third question - How many times I can use await keywords to query database asynchronously in ONE single action method?

As many as you like. However, note that many ORMs have a one-operation-per-connection rule. In particular, EF only allows a single operation per DbContext; this is true whether the operation is synchronous or asynchronous.

Also, keep in mind the scalability of your backend again. If you're hitting a single instance of SQL Server, and your IIS is already capable of keeping SQLServer at full capacity, then doubling or tripling the pressure on SQLServer is not going to help you at all.

Solution 3

is it good to use async action everywhere in ASP.NET MVC?

As usual in programming, it depends. There is always a trade-off when going down a certain path.

async-await shines in places where you know you'll receiving concurrent requests to your service and you want to be able to scale out well. How does async-await help with scaling out? In the fact that when you invoke a async IO call synchronously, such as a network call or hitting your database, the current thread which is responsible for the execution is blocked waiting for the request to finish. When you use async-await, you enable the framework to create a state machine for you which makes sure that after the IO call is complete, your method continues executing from where it left off.

A thing to note is that this state machine has a subtle overhead. Making a method asynchronous does not make it execute faster, and that is an important factor to understand and a misconception many people have.

Another thing to take under consideration when using async-await is the fact that it is async all the way, meaning that you'll see async penetrate your entire call stack, top to buttom. This means that if you want to expose synchronous API's, you'll often find yourself duplicating a certain amount of code, as async and sync don't mix very well.

Shall I use async/await keywords when I want to query database (via EF/NHibernate/other ORM)?

If you choose to go down the path of using async IO calls, then yes, async-await will be a good choice, as more and more modern database providers expose async method implementing the TAP (Task Asynchronous Pattern).

How many times I can use await keywords to query database asynchronously in ONE single action method?

As many as you want, as long as you follow the rules stated by your database provider. There is no limit to the amount of async calls you can make. If you have queries which are independent of each other and can be made concurrently, you can spin a new task for each and use await Task.WhenAll to wait for both to complete.

Solution 4

async actions help best when the actions does some I\O operations to DB or some network bound calls where the thread that processes the request will be stalled before it gets answer from the DB or network bound call which you just invoked. It's best you use await with them and it will really improve the responsiveness of your application (because less ASP input\output threads will be stalled while waiting for the DB or any other operation like that). In all my applications whenever many calls to DB very necessary I've always wrapped them in awaiatable method and called that with await keyword.

Solution 5

My 5 cents:

  1. Use async/await if and only if you do an IO operation, like DB or external service webservice.
  2. Always prefer async calls to DB.
  3. Each time you query the DB.

P.S. There are exceptional cases for point 1, but you need to have a good understanding of async internals for this.

As an additional advantage, you can do few IO calls in parallel if needed:

Task task1 = FooAsync(); // launch it, but don't wait for result
Task task2 = BarAsync(); // launch bar; now both foo and bar are running
await Task.WhenAll(task1, task2); // this is better in regard to exception handling
// use task1.Result, task2.Result
Share:
127,066

Related videos on Youtube

Vnuuk
Author by

Vnuuk

I'm an independent full stack ASP.NET, C# developer

Updated on July 08, 2022

Comments

  • Vnuuk
    Vnuuk almost 2 years

    I have some concerns using async actions in ASP.NET MVC. When does it improve performance of my apps, and when does it not?

    1. Is it good to use async action everywhere in ASP.NET MVC?
    2. Regarding awaitable methods: shall I use async/await keywords when I want to query a database (via EF/NHibernate/other ORM)?
    3. How many times can I use await keywords to query the database asynchronously in one single action method?
  • Panagiotis Kanavos
    Panagiotis Kanavos almost 9 years
    Regarding async, IIS and the database, the blog post is extremely old and the conclusions drawn here are wrong. IIS has to server a much larger load than the database, threadpool threads are limited and a long request queue can lead to 500. Anything that frees up a thread while waiting for IO is beneficial. Even the links are not about what the OP asked. In fact the same authors have written that you should use asynchronous DB methods wherever you can
  • Panagiotis Kanavos
    Panagiotis Kanavos almost 9 years
    Moreover, async doesn't mean parallel. Asynchronous execution frees a valuable threadpool thread from blocking for an external resource, for no complexity or performance cost. This means the same IIS machine can handle more concurrent requests, not that it will run faster.
  • Panagiotis Kanavos
    Panagiotis Kanavos almost 9 years
    Asynchronous db calls don't execute faster but allow the same IIS machine to server many more requests because threadpool threads aren't wasted. It also lowers CPU costs because blocking calls actually start with a CPU-intensive spinwait before actually blocking. In high load situations this can be the difference between the machine struggling or failing and recycling
  • Panagiotis Kanavos
    Panagiotis Kanavos almost 9 years
    You should also consider that blocking calls start with a CPU-intensive spinwait. During stress times, blocking calls will result in escalating delays and app pool recycling. Asynchronous calls simply avoid this
  • Yuval Itzchakov
    Yuval Itzchakov almost 9 years
    @PanagiotisKanavos I know, was that unclear from what I said?
  • Panagiotis Kanavos
    Panagiotis Kanavos almost 9 years
    Your answer doesn't mention the IIS specifics - the meltdown/recycle scenario is a primary reason to use async throughout. Someone who hasn't experienced it probably won't understand that scale out well may mean your server won't die under load. Or it may be a case of once burned ...
  • seebiscuit
    seebiscuit about 8 years
    Wouldn't the single database instance scenario benefit from freeing up a thread for, say, CPU-bound operations? No particular request would be faster, but the load on the server should be better optimized, enhancing the overall performance...
  • Stephen Cleary
    Stephen Cleary about 8 years
    @seebiscuit: No. Because you don't end up "freeing up a thread" - you just end up jumping threads. You can't free up a thread with a CPU-bound operation, because it needs a thread to run on. You can free up the request thread - by using another thread - but all that does is cause an additional thread switch and possibly throw off the ASP.NET thread pool balancing heuristics.
  • seebiscuit
    seebiscuit about 8 years
    Wow, very interesting. So I/O "free" threads are not available for CPU-bound ops?
  • Stephen Cleary
    Stephen Cleary about 8 years
    @seebiscuit: When doing (proper asynchronous) I/O, no threads are used. I have a blog post that goes into more detail.
  • KCD
    KCD about 8 years
    Excellent answer. If the IIS thread pool > than the DB connection pool is it a deadlock waiting to happen? Assume requests all wait for the I/O result. Was reading this: blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx
  • Stephen Cleary
    Stephen Cleary about 8 years
    No, I don't see how that would cause a deadlock.
  • Hoang Nguyen Huu
    Hoang Nguyen Huu almost 8 years
    Asynchronous usually means having a worker thread to do intensive work, freeing main thread from blocking task; but in case of ASP MVC I'm afraid it's not the same. @PanagiotisKanavos explained it well. And you can see the below answer for more detail.
  • Arwin
    Arwin almost 8 years
    Allow multiple result sets is a setting that I suppose overcomes the limitation on EntityFramework default 1 op per context limit?
  • Stephen Cleary
    Stephen Cleary almost 8 years
    @Arwin: I don't know.
  • MOD
    MOD over 7 years
    How many request can IIS and a single SQL Server instance handle? How can i find these numbers?
  • Stephen Cleary
    Stephen Cleary over 7 years
    @MOD: It depends on configuration and hardware. The only way to find these numbers is to do a load test on your own server.
  • Rob
    Rob over 7 years
    Since this is the accepted answer and thus at the top for most people, it might be wise to remove second first paragraph regarding execution times and running in parallel, which has nothing to do with async. I realize there's a note at the end, but it is quite misleading.
  • Flezcano
    Flezcano about 7 years
    Sorry for this silly question, what do you mean with "CPU-bound methods"?
  • Stephen Cleary
    Stephen Cleary about 7 years
    @Flezcano: Methods that execute fully on the CPU. I.e., they do not do I/O or blocking.
  • Learning-Overthinker-Confused
    Learning-Overthinker-Confused almost 7 years
    I am having 1 web api end point.Now if 1000 request hit this endpoints simultanoeusly does my code is responsible to handle this 1000 request like making this end point as fire and forget or this depends upon server and iis capability?
  • Stephen Cleary
    Stephen Cleary almost 7 years
    @Learning: Sorry, I don't understand the question, but it doesn't appear to be a clarification of this question/answer. Please ask a separate question on SO.
  • Learning-Overthinker-Confused
    Learning-Overthinker-Confused almost 7 years
    Sorry sir but SO wont accept this 2 liner question which i am trying to understand.when i was researching for this thing like if i have 1 web api end point which is called by 1000 users at same time then will this end point would be able to server each of this thousand request or i should make it async to handle 1000 of request?
  • JustAMartin
    JustAMartin almost 5 years
    Asynchronous execution frees a thread only in cases when it's truly async down to the very bottom of the implementation and uses some callback mechanism to signal readyness and to spin up a new thread to switch the context and process the result. So, I'm not sure in which cases this context switching / new thread creation is more efficient than just waiting for results in a single thread? Long running web service calls are a bad idea anyway, I prefer to offload it to a reliable background service and let the client check for results, which might come in a few minutes, hours or days.
  • JustAMartin
    JustAMartin almost 5 years
    Business logic for most web apps usually need highly sequential operations, so jumping between parallel processes in most cases is viable only at the very top level of the web request / worker process management, which doesn't deal with database requests directly anyway. I would really want to see some real world examples of a typical web application where it would be actually a good idea to process DB queries in async manner.