Coder Perfect

In ASP.NET MVC, when should I utilize Async Controllers?


In ASP.NET MVC, I have certain reservations about using async activities. When does it help my apps function better, and when does it not?

Asked by Vnuuk

Solution #1

You might find my MSDN article on the subject useful; I spent a lot of time in that post detailing when and how to utilize async in ASP.NET, not simply how to use it.

To begin, remember that async/await is about freeing up threads. It’s primarily about freeing up the GUI thread in GUI apps to improve the user experience. It’s primarily about freeing up the request thread in server applications (including ASP.NET MVC) so that the server can scale.

It won’t, in particular:

It’s good to utilize it everywhere you’re conducting I/O, in my opinion. However, it isn’t always advantageous (see below).

However, it’s not a good idea to use it for CPU-intensive procedures. Some developers believe that by simply calling Task, they may achieve the benefits of async. This is a terrible idea to run in their controllers. Because that code frees up the request thread by creating a new thread, there’s no advantage (and they’re actually incurring the cost of extra thread switches)!

You could utilize whatever awaitable methods you have at your disposal. The majority of the main players currently support async, while a few do not. Don’t try to wrap your ORM in Task if it doesn’t support async. Run or something similar (see above).

It’s important to note that I mentioned “you could utilize.” If you’re using ASP.NET MVC with a single database backend, async is almost probably not going to help you scale your application. This is due to the fact that IIS can handle significantly more concurrent queries than a single SQL server instance (or other classic RDBMS). If your backend is more current – a SQL server cluster, Azure SQL, NoSQL, etc. – and your backend can scale, and IIS is your scaling constraint, then async can help you scale.

You may have as many as you want. However, many ORMs impose a one-operation-per-connection restriction. EF, in particular, enables exactly one operation per DbContext, regardless of whether it is synchronous or asynchronous.

Also, remember to consider your backend’s scalability. If you’re hitting a single instance of SQL Server and your IIS is already capable of keeping SQLServer busy, doubling or tripling the load on SQLServer won’t help you at all.

Answered by Stephen Cleary

Solution #2

When an action must conduct numerous distinct long-running activities, asynchronous action methods are in handy.

Is it necessary for my database calls to be asynchronous?

When compared to a database server, the IIS thread pool can generally manage much more simultaneous blocking requests. Asynchronous calls will not speed up the database response if the database is the bottleneck. 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.

Take a look at the first and second references.

Adapted from @PanagiotisKanavos’s remarks:

Answered by Tharif

Solution #3

It depends, as it always does in programming. When taking a given course, there is always a trade-off.

Async-await shines in situations when you know your service will receive multiple concurrent requests and you need to scale out well. When it comes to scaling out, how can async-await help? 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.

It’s worth mentioning that this state machine has a slight overhead. Making a method asynchronous does not make it execute faster, which is a critical distinction to make and a common misunderstanding.

Another thing to remember while using async-await is that it is async all the way, which means that async will pervade your entire call stack from top to bottom. As a result, if you wish to expose synchronous APIs, you’ll almost always have to duplicate some code, because async and sync don’t mix well.

Yes, async-await will be a smart alternative if you choose to use async IO calls, as more and more modern database providers have async methods implementing the TAP (Task Asynchronous Pattern).

As many as you want, as long as you follow your database provider’s standards. The number of async calls you can make is unlimited. You can use await Task to spin a separate task for each query that is independent of the others and can be run concurrently. WhenAll you have to do is wait for both of them to finish.

Answered by Yuval Itzchakov

Solution #4

Async actions are most useful for doing I/O operations on a database or making network calls, as the thread processing the request will be paused until it receives a response from the database or network call you just called. It’s recommended if you utilize await with them, since it will greatly increase your app’s responsiveness (because less ASP input\output threads will be stalled while waiting for the DB or any other operation like that). When several calls to the database are required in my applications, I always wrap them in an awaiatable method and call it with the await keyword.

Answered by Dimitri

Solution #5

My 5 cents:

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

As an added bonus, you can do a few IO calls in parallel if necessary:

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

Answered by bohdan_trotsenko

Post is based on