Showing posts with label Async and Performance. Show all posts
Showing posts with label Async and Performance. Show all posts

Friday, April 3, 2015

ASP.NET Async Tips


  • Avoid using background threads in ASP.NET as there are no background threads on servers unlike a WPF or Console application. For the latter, it may be a good idea to keep the async work separate from the main UI thread to avoid locking up the UI. But there is no separate UI thread for Web Applications to lock up! 

  • Doing so gives up the current thread for processing other requests, but you end up taking another thread from the same thread pool, only adding up the cost for a thread swap for no reason. All threads come from the same pool used to serve requests. Moving to another thread just adds cost.

  • If indeed you need a real background thread legitimate reason, consider using SynchronizationContext.Post which can be used in a thread safe manner.

  • Avoid using Task.Wait in ASP.NET like the plague. It is blocking and often causes deadlocks. Deadlocks occur because the framework spins up locks to make thread run thread-safe. But in ASP.NET if blocking using Task.Wait on the same thread it is very easy to cause a deadlock with async code.

  • Avoid Task.ContinueWith as it is not aware of SynchronizationContext and always puts you on a new thread! This has become redundant with await and await is aware of SynchronizationContext is the task does end up running in a separate thread.

  • Be careful with parallelism on the ASP.NET server. Multiple requests * multiple threads can quickly lead to thread starvation for as all threads come from the same pool. Threads consume minimum of 1/4 MB each.

  • However kicking off multiple awaitable async tasks is fine. This actually helps scale your application better as the same thread can serve multiple tasks in an async manner.

  • Don't call fire and forget methods - methods that don't return anything as your void methid code could be terminated anytime the original request ended to return the thread to the thread pool! If needed, use WebBackgrounder from http://nuget.org/packages/webBackgrounder

Check out these references:

Parallel Programming with .NET Blog
http://blogs.msdn.com/pfxteam/

Asynchrony in .NET Whitepaper
http://msdn.com/library/vstudio/hh191443.aspx

ASP.NET Async Tutorial
http://www.asp.net/web-forms/tutorials/aspnet-45/using-asynchronous-methods-in-aspnet-45

Task Parallelism Usage Pattern using Async in ASP.NET

1) Use a list of tasks

var tasks = new List<Task<string>>
{
      CreateHtmlTextFirstAsync(),
      CreateHtmlTextSecondAsync(),
      CreateHtmlTextLastAsync()
};

2) Process tasks if any left in a while loop, removing completed task within the loop.
     Keep flushing out the completed contents of each task as it completes in the loop.
     (Note: Commenting out the check for IsFaulted that would not display content if the task had faulted, as this check may not be correctly coded here)

context.Response.ContentType = "text/html";
context.Response.Write(@"<!DOCTYPE html><html><body>");
context.Response.Write(@"<title>Async Body Sections!</title>");

while (tasks.Any())
{
      var completed = await Task.WhenAny(tasks);
      task.Remove(completed);
   
      //if (!completed.IsFaulted)
      //{
            context.Response.Write(completed.Result);
            context.Response.Flush();
     // }
}

context.Response.Write(@"</body></html>");

**********************************************

We can improve the above code further by making the Response.Flush run asynchronously.
There is no async method for it, but we can make use of Task class like so and make it awaitable:

await Task.Factory.FromAsync(context.Response.BeginFlush, context.Response.EndFlush, null);


Async Cancellation Tokens

ASP.NET has 3 built in Cancellation tokens that allow us to terminate an in-flight async task - say cancel even a database query that is executing. For instance, when the token is marked as Cancel, then ASP.NET terminates the async task to return the thread back to the threadpool.

The three built-in tokens are:

  • RequestTimeout - request timed out so discontinue
  • ClientDisconnected - client closed the browser, so discontinue async work
  • AsyncTimeout - set a timeout for my async task


Note: Always use RegisterAsyncTask when doing async code in ASP.NET. It is a best practice.

Example code snippet on Page_Load of ASP.NET Webforms,

RegisterAsyncTask(new PageAsyncTask(async ()=>
   {
      var token = Response.ClientDisconnectedToken;

       var stockJson = await new HttpClient().GetStringAsync(Constants.StockServiceUri, token);
       var stock = JsonConvert.DeserializeObject<Stock>(stockJson);
       DisplayStock(stock);

       var rssXml = await new HttpClient().GetStringAsync(Constants.RssUri, token);
       var rss = Desserialize(rssXml);
        DisplayRss(rss);
   }));

Note: The GetStringAsync is an extension method you can define as

public static class HttpClientExtensions
{
      public static async Task<string> GetStringAsync(
                 this HttpClient client,
                 string requestUri,
                 CancellationToken token) // this parameter is optional!!
     {
           var response = await client.GetAsync(requestUri, token);
           var result = await response.Content.ReadAsStringAsync();
           return result;
     }
}

**************************************************************************

The Webforms, WebAPI and MVC APIs allow only passing in one token object at a time, so we can wire all three tokens in a single object and pass it in! We can build a composite token this way,

var source = CancellationTokenSource.CreateLinkedTokenSource(
      Response.ClientDisconnectedToken,
      Request.TimedOutToken,
      t); //where t is the AsyncTimeOut token

//Use this composite source object
var token = source.Token;

Make sure to pass in "t" as a parameter to the lambda expression for PageAsyncTask like so

new PageAsyncTask(async (t) =>

*************************************************************************

WebApi and MVC actually makes this simpler by simply taking in a CancellationToken parameter in its method signatures. Also retrospectively adding this parameter does not affect any existing clients that don't pass in this token.

Example WebApi Get,

private StockContext entityDb = new StockContext();

public async Task<Stock> Get(CancellationToken token)
{
     return await entityDb.Stocks.FirstAsync(token);
}

Takeaways:

  1. Cancellation tokens further reduce thread usage and supplement async/await
  2. ASP.NET has built-in Cancellation tokens
  3. Use CancellationTokenSource to combine tokens


Saturday, March 21, 2015

Deadlock Async Await

Avoid using Task.Wait or Task.Result while calling async code as this would block on calling the async code. Any code that blocks on calling async code could cause deadlocks. Example:

public static class DeadlockAsyncTaskWait
{
  private static async Task DelayAsync()
  {
    await Task.Delay(1000);
  }
  
  // This method causes a deadlock when called in a GUI or ASP.NET context.
// Will work just fine when calling from a console app!
  public static void Test()
  {
    // Start the delay.
    var delayTask = DelayAsync();
    
    // Wait for the delay to complete.
    delayTask.Wait();
  }
}

Moral of the story: Go async all the way and use async await. That's just the nature of asynchronous coding

Reference : https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

Saturday, February 22, 2014

Async methods in ASP.NET 4.5

This one is an useful read from Scott Hanselman's post, particularly the comments from Stephen Cleary

http://www.hanselman.com/blog/TheMagicOfUsingAsynchronousMethodsInASPNET45PlusAnImportantGotcha.aspx

Friday, August 30, 2013 9:54:09 AM UTC
@Ben, @Daniel: You should not use Task.Run on the server side. It makes sense on the client (to free up the UI thread), but it does not make sense on the server side (you're freeing up a worker thread... by using another worker thread). This is covered in an excellent video on Channel9.

@Daniel: You should not use Task.Result in async code; it's easy to cause deadlocks.

@Ben: All three tasks are running when you call the first await, so even though that method is suspended, the other tasks are already running.

@MarcelWijnands: It's the difference between "wait for the first task, then continue the method, wait for the second task, then continue the method, wait for the third task, then continue the method" and "wait for all tasks, then continue the method". The Task.WhenAll approach has less switching back and forth.


Also from Stephen, never block on async code on a synchronous method (using Task.Wait()) like so

Figure 3 A Common Deadlock Problem When Blocking on Async Code

1.public static class DeadlockDemo
2.{
3.  private static async Task DelayAsync()
4.  {
5.    await Task.Delay(1000);
6.  }
7.  // This method causes a deadlock when called in a GUI or ASP.NET context.
8.  public static void Test()
9.  {
10.    // Start the delay.
11.    var delayTask = DelayAsync();
12.    // Wait for the delay to complete.
13.    delayTask.Wait();
14.  }
15.}

Monday, February 17, 2014

A scenario when to use Func/Action

Can you tell the difference between the following 2 code snippets?

1) Using a Func/Action within a static method

public static class ExpensiveMethodWithAFuncClass<T>
{
      public static readonly Func<T> ExpensiveMethod= ExpensiveMethodImplementation();
      private static Func<T> ExpensiveMethodImplementaion
     {
           //some expensive operations here
          // returns a compiled delegate
     }
}

2)  Same class without using a Func<T>

public static class ExpensiveMethodClass<T>
{
      public static T ExpensiveMethod
     {
         //build the expression here, compile and invoke the expression
      }
}

Answer :  In 1) when we call ExpensiveMethod, the implementation ExpensiveMethodImplementation() is executed only once.

In the case of 2) we will execute ExpensiveMethod every time we call it.

 If the implementation is an expensive operation, 1) will benefit from using the delegate Func<T>