Asynchrony in .NET


Microsoft recently released a whitepaper on the future of Asynchrony in .NET along with a CTP SDK.

This CTP attempts to address one concern:  how to make asynchrony easy in .NET by removing all the friction in code.

In .NET, Asynchrony, so far, as been treated with the pattern BeginXYZ / EndXYZ dynamic duo.  For instance, in the System.Web.UI.Page class, you can either use the synchronous ProcessRequest or the asynchronous pair AsyncPageBeginProcessRequest / AsyncPageEndProcessRequest.

This pattern works.  It does deliver the goods and if you implement it throughout your code, you’ll rip the benefits of scalability (in that your threads won’t be blocked waiting for IO work) given by asynchrony.  This work will also come with a slight side-effect:  your code will be very hard to read and debug.  The reason, and it is very well explained in the whitepaper, is that this pattern disrupt the control flow.

The basic reason is that when you use this pattern, you work with call backs.  Instead of having one method, you have two:  one invoking the asynchronous work, the other one being called back once the asynchronous work is done.

To use an example given in the whitepaper, here is your synchronous code:

public int SumPageSizes(IList<Uri> uris)
{
     int total = 0;

     foreach (var uri in uris)
     {
         statusText.Text = string.Format("Found {0} bytes ...", total);

         var data = new WebClient().DownloadData(uri);
         total += data.Length;
     }
     statusText.Text = string.Format("Found {0} bytes total", total);

     return total;
}

versus the asynchronous version (on download data):

public void SumPageSizesAsync(IList<Uri> uris)
{
     SumPageSizesAsyncHelper(uris.GetEnumerator(), 0);
}

private void SumPageSizesAsyncHelper(IEnumerator<Uri> enumerator, int total)
{
     if (enumerator.MoveNext())
     {
         statusText.Text = string.Format("Found {0} bytes ...", total);

         var client = new WebClient();

         client.DownloadDataCompleted += (sender, e) =>
         {
             SumPageSizesAsyncHelper(enumerator, total + e.Result.Length);
         };
         client.DownloadDataAsync(enumerator.Current);
     }
     else
     {
         statusText.Text = string.Format("Found {0} bytes total", total);
         enumerator.Dispose();
     }
}

Another great example of the complexity emerging from a simply control flow when put in asynchrony is this MSDN article on Asynchronous pages in ASP.NET 2.0:

http://msdn.microsoft.com/en-us/magazine/cc163725.aspx

So basically, the pattern exists but it’s so convoluted that its usage isn’t widespread.  Now what are the consequences?

Well, efficiency mostly.  It means that every time you need to access an external resources (File, DB, Web Service), you use a thread to wait for that resource to come back to you.  You basically burn gas.

Enters the new asynchrony pattern.  Let’s take the previous example (from the whitepaper), with the new async language support:

public async Task<int> SumPageSizesAsync(IList<Uri> uris)
{
     int total = 0;

     foreach (var uri in uris)
     {
         statusText.Text = string.Format("Found {0} bytes ...", total);
         var data = await new WebClient().DownloadDataAsync(uri);
         total += data.Length;
     }
     statusText.Text = string.Format("Found {0} bytes total", total);

     return total;
}

Wow, that looks awfully the same as the synchronous version, doesn’t it?  What are the differences?  Well, they are already highlighted.

The key:  async & await keywords.  Those are new language construct.  Remember .NET 2.0 yield keyword?  Think of it as something similar, because your friendly compiler is going to work as hard with the new keywords!

Basically, it means that this method isn’t just returning the total as it seems to do, it returns a task (a .NET 4.0 class representing an asynchronous piece of work) returning an integer.

The compiler will tear the method apart to basically let the start of the method until the await execute synchronously and the rest as a call back.  Better yet, it does so by capturing the synchronization context of the original thread and execute each bit of the method on that synchronization context.

There is much more to say about what those keywords are doing, but I would just duplicate what is written in the whitepaper.  I just wanted to tease in order to read it, so go on and read it!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s