120

What is the difference between:

public ActionResult Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        IdentityResult result = IdentityManager.Authentication.CheckPasswordAndSignIn(AuthenticationManager, model.UserName, model.Password, model.RememberMe);
        if (result.Success)
        {
            return Redirect("~/home");
        }
        else
        {
            AddErrors(result);
        }
    }
    return View(model);
}

and:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        IdentityResult result = await IdentityManager.Authentication.CheckPasswordAndSignInAsync(AuthenticationManager, model.UserName, model.Password, model.RememberMe);
        if (result.Success)
        {
            return Redirect("~/home");
        }
        else
        {
            AddErrors(result);
        }
    }
    return View(model);
}

I see that the MVC code now has async but what is the difference. Does one give much better performance than the other? Is it easier to debug problems with one than the other? Should I make changes to other controllers for my application to add Async ?

annemartijn
  • 1,538
  • 1
  • 23
  • 45
  • In the vast majority of situations there's no serious benefit for using async in MVC, however there are many negatives – Chris Marisic Oct 22 '16 at 20:55
  • 1
    @ChrisMarisic - One of the most serious: you can't use ReaderWriterLock or any of the other synchronization primitives (except for Semaphore). – Quark Soup Dec 19 '18 at 15:45

3 Answers3

170

The async actions are useful only when you are performing I/O bound operations such as remote server calls. The benefit of the async call is that during the I/O operation, no ASP.NET worker thread is being used. So here's how the first example works:

  1. When a request hits the action, ASP.NET takes a thread from the thread pool and starts executing it.
  2. The IdentityManager.Authentication.CheckPasswordAndSignIn method is invoked. This is a blocking call -> during the entire call the worker thread is being jeopardized.

And here's how the second call works:

  1. When a request hits the action, ASP.NET takes a thread from the thread pool and starts executing it.
  2. The IdentityManager.Authentication.CheckPasswordAndSignInAsync is called which returns immediately. An I/O Completion Port is registered and the ASP.NET worker thread is released to the thread pool.
  3. Later when the operation completes, the I/O Completion port is signaled, another thread is drawn from the thread pool to finish returning the view.

As you can see in the second case ASP.NET worker threads are used only for a short period of time. This means that there are more threads available in the pool for serving other requests.

So to conclude, use async actions only when you have a true async API inside. If you make a blocking call inside an async action, you are killing the whole benefit of it.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • How about context synchronization. Won't this be such an overhead that you do not want to use async actions at all? "The overhead of an async method which actually executes asynchronously depends entirely on whether it needs to switch threads using SynchronizationContext.Post. If it does, the overhead is dominated by the thread switch it performs as it resumes. That means that the current SynchronizationContext makes a big difference." (Async in C# 5.0, 2012, Alex Davies) – annemartijn Mar 22 '14 at 21:46
  • 1
    @Darin Why is it so important to release the main thread? Are thread limited? – Omtechguy Dec 22 '14 at 20:33
  • 1
    @Omtechguy a better solution is to move non ASP.NET requests to a CDN. A simple CDN is merely using subdomain and separate app pool for physical files like your javascript and images. Alternatively you could use NgineX / Lighttpd / Apache for files, or you could use a third party service such as Akamai (king for CDN but most expensive) – Chris Marisic Oct 22 '16 at 21:00
  • I'm still confused. When the `CheckPasswordAndSignInAsync` is called, ASP.NET takes another thread from the thread pool and starts executing it, doesn't it? If it doesn't, where is `checking password procedure` executed in? – KevinBui Dec 15 '17 at 08:26
2

Normally, a single HTTP request would be handled by a single thread, completely removing that thread from the pool until a response is returned. With the TPL, you are not bound by this constraint. Any request that come in starts a continuation with each unit of computation required to calculate a response able to execute on any thread in the pool. With this model, you can handle many more concurrent requests than with standard ASP.Net.

If it is some new task that will be spawned, or not, and if it should be awaited or not. Always think about those 70 ms, which is approx. the max. time that any method call should take. If its longer, then your UI will most probably not feel very responsiveness.

0

In web applications that sees a large number of concurrent requests at start-up or has a bursty load (where concurrency increases suddenly), making these web service calls asynchronous will increase the responsiveness of your application. An asynchronous request takes the same amount of time to process as a synchronous request. For example, if a request makes a web service call that requires two seconds to complete, the request takes two seconds whether it is performed synchronously or asynchronously. However, during an asynchronous call, a thread is not blocked from responding to other requests while it waits for the first request to complete. Therefore, asynchronous requests prevent request queuing and thread pool growth when there are many concurrent requests that invoke long-running operations.

Muhammad Essa
  • 142
  • 1
  • 10
  • If your aspnet application largely consists of calls to other web servers, you're largely behaving as a 'gateway' / 'proxy' and async is useful for that purpose. – Chris Marisic Dec 20 '18 at 21:42