Saturday 31 March 2012

ASP.NET Web API Series - Part 2: Async basics and background

[Level T2]

Async is here, async is there, async is everywhere. [For a newer related post see here]

Not sure above line is from which film (or did I just make it up?) but surely a quick look at the ASP.NET MVC 4 and its Web API features just shows how much asynchronous programming is encouraged.

In this short post, I just want to cover some of the basics and background for async in Web API without going  into async keyword or .NET 4.5 features. Remember, all of the async features of ASP.NET Web API is accessible in .NET 4.0 and VS 2010 without using VS 2011 and async keyword. It is true, though, that with new language features expected in .NET 4.5 this would be even more tersely possible.

One of the obvious reasons asynchronous programming is encouraged is the fact that servers nowadays run tens of parallel processors and ability to run the code in parallel is very important.

Yet, I would also like to see this from another angle. I do not want to approach this as a conspiracy theory but I think there is an important change in IIS that we need to be aware of which affects scalability of ASP.NET Web Applications. OK, will give you a clue: what was the fundamental architecture change from IIS 6.0 to IIS 7.0? Well, yes, integrated pipeline! So let's look at how it affects the threading in IIS.

This was actually a question that I answered in StackOverflow. When I was reviewing this I looked around and found my own answer from last year. It can probably tell you a bit how terrible my memory is! So one of the changes was (a good background here) to remove the limitation of ASP.NET on the number of threads (if I remember correctly, IIS 6.0 had 250 threads per application pool) and only have a limitation on the number of requests queued. This can be set per each application pool in the advanced settings menu:


As the above article mentions, IIS 7.0's integrated pipeline is as scalable as amount of work done async:
... in IIS 7.0 integrated mode, ASP.NET restricts the number of concurrently executing requests. The difference only matters when the requests are asynchronous (the request either has an asynchronous handler or a module in the pipeline completes asynchronously). Obviously if the reqeusts are synchronous, then the number of concurrently executing requests is the same as the number of threads concurrently executing requests, but if the requests are asynchronous then these two numbers can be quite different as you could have far more reqeusts than threads.
So basically, the more async is used for long-running IO-bound operations (talking to other services, reading from disk, connecting to databases), the more threads are free to process incoming requests. This is particularly important in the light of the fact that serving static content under integrated pipeline has to go through ASP.NET runtime hence each using up a thread. So if you have 500 concurrent users and they are loading a page each containing 5 static content, if there is no Async used, some of these users will experience 503 errors for some of the content as the queue will get full.

Now, let's see how we can use Async in ASP.NET Web API in .NET 4.0 without using async keyword which is introduced in .NET 4.0.

All you have to do is to return a started Task<T>. Note the started, if you just create and return the task, the response will not return back from server and request will be timed out.

So here is a typical Async task:
  
  
   // GET /api/HelloWorld
  [HttpGet]
  public Task<string> AsyncCall()
  {
   return
    Task.Factory.StartNew<string>(
     () =>
     {
      Thread.Sleep(5000);
      return "Hello World";
     }
    );
    
  }

This is a minor enhancement on our HelloWorldController and in order to simulate the long running task, I have put a Thread.Sleep for 5 seconds. Now if you browse, you will experience a noticeable delay (for 5 seconds) before you get back the response.

Now the question is, does the task really runs in a different thread? Well, easy to test. All we have to do is to name the controller thread and see if the task thread name is the same:

  
  // GET /api/HelloWorld
  [HttpGet]
  public Task<string> AsyncCall()
  {
   Thread.CurrentThread.Name = "AsyncCall";
   return
    Task.Factory.StartNew<string>(
     () =>
     {
      Thread.Sleep(5000);
      return "This is the thread name:" + Thread.CurrentThread.Name;
     }
    );
    
  }
  
The result is:
  
      "This is the thread name:"

So the thread name was empty string proving the thread doing the task was indeed different.

Conclusion


Use of Async programming with the help of PTL is highly encouraged especially in IIS 7.0. This will improve scalability of the web application and is very easy to do.

For more in depth Async coverage, move on to the next post Async Deep Dive.

1 comment:

  1. I'm sure the movie you're thinking of is "The Scarlet Pimpernel" with Leslie Howard in the title role.

    Best regards,

    -John

    ReplyDelete

Note: only a member of this blog may post a comment.