Making Asynchronous Programming Easy


Writing applications that effectively handle long latencies can be a daunting challenge.  As software applications grow more complex, more developers are building software that accesses remote resources, performs longer computations, and processes large data sets.  Tasks we used to think of as being quick now may take orders of magnitude longer to complete or may never complete.  Without special care taken to manage conditions that may arise from these latencies, applications can become unresponsive or unable to scale.  To accommodate these conditions, C# and VB are adopting a new asynchronous programming model.

Existing asynchronous programming paradigms provide ways to work with I/O and other high-latency operations without blocking threads. However, the current patterns are often difficult to understand and can complicate the simplest operations with callbacks and custom exception handling, resulting in error-prone code or developers simply giving up. With Async, our goal now is to make asynchronous programming far more approachable so asynchronous code is as easy to write and maintain as synchronous code. Making your code asynchronous should require only simple changes and should be possible to implement in a non-disruptive manner in your code. At the same time, it should be evident when code is “going async” so that the inherently-concurrent nature of the method can be understood at a glance.

Today, we are unveiling significant language and framework enhancements in C# and Visual Basic that enable developers to harness asynchrony, letting them retain the control flow from their synchronous code while developing responsive user interfaces and scalable web applications with greater ease.   This CTP delivers a lightweight asynchronous development experience as close to the standard synchronous paradigms as possible, while providing an easy on-ramp to the world of concurrency.

The Old Way

The C# and VB code snippets below show how asynchronous code is written today.  I have defined a SumPageSizesAsync method that asynchronously calls a WebClient to retrieve multiple sources of data, leaving the UI responsive while multiple data requests execute against remote servers.  I want to wait for all the requests to complete before calling the caller’s callback method.  The code doesn’t flow naturally, with code split across two methods and a callback to handle exception cases that can arise in two places.  In addition, since a foreach statement cannot span across async calls, a lambda expression calls the second method again, complicating what should be simple logic and exposing several places where mistakes could be introduced.

public void SumPageSizesAsync(IList<Uri> uris, Action<int, Exception> callback) {
    SumPageSizesAsyncHelper(uris.GetEnumerator(), 0, callback);
}
  
private void SumPageSizesAsyncHelper(IEnumerator<Uri> enumerator, int total, 
                                     Action<int, Exception> callback) {
    try {
        if (enumerator.MoveNext()) {
            statusText.Text = string.Format("Found {0} bytes ...", total);
            var client = new WebClient();
            client.DownloadDataCompleted += (sender, e) => {
                if (e.Error != null) 
                {
                    enumerator.Dispose();
                    callback(0, e.Error);
                }
                else SumPageSizesAsyncHelper(
                    enumerator, total + e.Result.Length, callback);
            };
            client.DownloadDataAsync(enumerator.Current);
        }
        else {
            statusText.Text = string.Format("Found {0} bytes total", total);
            enumerator.Dispose();
            callback(total, null);
        }
    }
    catch (Exception ex) {
        enumerator.Dispose();
        callback(0, ex);
    }
}
Public Sub SumPageSizesAsync(uris As IList(Of Uri), 
                             callback As Action(Of IntegerException))
    SumPageSizesAsyncHelper(uris.GetEnumerator(), 0, callback)
End Sub
 
Private Sub SumPageSizesAsyncHelper(
        enumerator As IEnumerator(Of Uri),
        total As Integer,
        callback As Action(Of IntegerException))
    Try
        If enumerator.MoveNext() Then
            statusText.Text = String.Format("Found {0} bytes ...", total)
            Dim client = New WebClient()
            AddHandler client.DownloadDataCompleted,
                Sub(sender, e)
                    If e.Error IsNot Nothing Then
                        enumerator.Dispose()
                        callback(0, e.Error)
                    Else
                        SumPageSizesAsyncHelper(
                            enumerator, total + e.Result.Length, callback)
                    End If
                End Sub
            client.DownloadDataAsync(enumerator.Current)
        Else
            statusText.Text = String.Format("Found {0} bytes total", total)
            enumerator.Dispose()
            callback(total, Nothing)
        End If
    Catch ex As Exception
        enumerator.Dispose()
        callback(0, ex)
    End Try
End Sub

The New Way

Async CTP introduces a new keyword await, which indicates that the caller would like control to return when an asynchronous method call has completed.  With the await keyword in Async, the code snippet above now has less than half the code, and we’ve regained the use of simple control flow constructs such as ‘foreach’.  Also, notice that the try block is no longer required – this is because any exceptions that occur now bubble up to callers naturally, just as they do in synchronous code.

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().DownloadDataTaskAsync(uri);
        total += data.Length;
    }
    statusText.Text = string.Format("Found {0} bytes total", total);
    return total;
}
Public Async Function SumPageSizesAsync(uris As IList(Of Uri)) As Task(Of Integer)
    Dim total As Integer = 0
    For Each uri In uris
        statusText.Text = String.Format("Found {0} bytes ...", total)
        Dim data = Await New WebClient().DownloadDataTaskAsync(uri)
        total += data.Length
    Next
    statusText.Text = String.Format("Found {0} bytes total", total)
    Return total
End Function

This gives you the best of both worlds – responsive client apps and scalable server apps enabled by asynchronous programming models, along with the straightforward coding style of traditional synchronous code. 

Try It Out

Async CTP is an early preview of the new asynchronous programming pattern for C# and VB, and we’d like to hear your feedback.  Download the bits, then join the conversation.

Namaste!

Comments (14)

  1. Joe White says:

    This may seem like a small thing, but shouldn't you be disposing the WebClient when you're done with it? Or does "await" and/or DownloadDataTaskAsync somehow manage that for you? If so, how?

  2. John Marlin says:

    It looks like you announced async programming for F# a year ago, blogs.msdn.com/…/f-in-vs2010.aspx

    Anyway, the F# guys and Microsoft Research deserve a lot of credit for this: the C# feature does look like a copy of the F# feature, and I'm sure they'll work well together. It would be nice to see that mentioned.

  3. Rex Nfx says:

    Does this work in any version of silverlight? If so, which version did it first appear? I've been using the old async approach recently. I still have not had any success uploading stuff from the client and getting a response from the server whether the upload was successful or not.

  4. Aaron says:

    Ok, so now it seems we have Rx Extensions, PLINQ, and now this.  Seems like an awful lot to choose from.  A blog post on when and how to leverage each of these would be extremely helpful.  

    I'm betting that there'll be a ton of overlap in their usage.

    I'm kind of feeling another PRISM vs MEF debacle coming on.  Sure, they do some things differently and provide some functionality that the other does not.  But there's a ton of functionality overlap.

  5. Tom says:

    I guess what people need to understand is that these are features that will be added into the language (and the .NET Framework) itself. Yes, these features will work for Silverlight. F# or C# – these are products of the same company. There are many features in VB.NET that have been picked up from C# – no one makes a big deal out of it…

  6. madstorgersen says:

    Thank you all for these great comments. Having worked on the Async features for well over a year now, it is great to finally be able to share it and get such good and varied feedback.

    @Joe: I guess eagerly disposing the WebClient would be neater, though it doesn't make much difference for WebClient. Luckily await also works inside of using statements!

    @John: You are very right that F# was a big inspiration for this. The VB and C# feature looks very similar on the surface but actually works very differently under the hood – while the F# experience translates well, the technology wasn't so easily reapplied. We worked closely with the F# team throughout the design process and made sure they work great together.

    @Rex: The Async CTP works with Silverlight 4.The Task type isn't in Silverlight 4, so the CTP adds it in. Since the language feature has a dependency on Framework API that isn't yet there (in both desktop and Silverlight), an eventual shipping version will not work "downlevel" on earlier frameworks.

    @Aaron: The Async CTP features build on the Task parallel library, which is already there. It is intended to be THE way you do asynchrony on .NET. PLinq is great for data parallelism, and Rx is great for composing event streams (but is not part of the .NET Framework). The Rx team has just released a version that integrates with the Async CTP: The two technologies are very complimentary and work well together.

    @Tom: The Async CTP indeed already has a high degree of interoperability with existing technologies – including F#. This will of course be an important theme if we ship it in a product.

    If you want to take a deeper look at the Async CTP, do check out the website. There is also a lot of buzz coming out of the PDC conference right now; you can pick up the latest with Bing.

    Thanks again,

    Mads Torgersen, C# Language PM @ Microsoft

  7. Joe says:

    Visual Studio is nothing but overlap – 100's of ways to do everything BUT none work right without hacks and work arounds which never get fixed instead you keep introducing new nonsense that only creates a new set of problems, MVC come to mind, that further reduces our productivity.

    As Soma said as applications grow more complex, perhaps if you guys could turn out better development tools that actually are finished, application development wouldn't be so complex. Look at the complexity being added to web development because IE can't follow standards or figuring out what unfinished .NET this or that framework to use. Being on a constant learning curve and working with Microsoft is totally draining. You should rename this product to Visual CTP. I seriously don't even think Visual Studio is an end user tool anymore Microsoft writes what they need for their internal development then releases it to the developer community to make a buck or two.

    I have never seen a bigger mess in my life then this product. I long for the day when it gets in end of life.

  8. Sam says:

    The async addition to C#/.NET is a welcoming change and adds a lot of value. However:

    Soma: Please explain to us – What was the message from PDC 2010 to .NET developers? Particularly the Silverlight developers! Virtually no mention of Silverlight during the keynote. It seems Microsoft doesn't think its important to mention a technology it has been touting for past 2-3 years. You guys are putting your energy into HTML 5 at the expense of Silverlight. Wow! What a turn! It would not have hurt and probably would have calmed everyone that you would focus on both. Bob Muglia said it very directly and it will hurt the faith that .NET developers have in any new technology that Microsoft promotes in the near future. Granted Microsoft has kept Silverlight for Windows Phone development, but that means you are limiting Silverlight and also taking it out of your grand plans going forward for the web, desktops, TV, etc.

    Further, it seems Microsoft has this terrible habit of looking at what the crap open-source people are doing, what is Ruby doing, what Python is doing, what PHP is doing and you guys try to incorporate their style/patters into ASP.NET and other .NET technologies resulting in a spaghetti style coding and un-wanted choices in ASP.NET/Silverlight. Can you guys share with us the percentage/number of developers are using MVC vs. regular way of coding ASP.NET websites? Adding MVVM to Silverlight has been a mega-disaster so far with the IDE itself shying away from full MVVM support. WCF RIA Services is a joke. It does not support using ADO.NET with stored procedures cleanly and drastically changes the way to write code in Silverlight apps. This is complete madness. SLOW DOWN and think and re-think before you guys add all sorts of ways of doing things just because a certain group of users/people give you feedback with strong opinions and requests.

  9. Rick says:

    @Sam I agree MVC usage would be interesting, I read somewhere it wasn't near 5% yet. I assume if MVC was building a strong corporate base Microsoft would be stating it, the quick introduction of the Razor view engine IMHO is a sign they totally missed the mark. Our company recently halted all R and D with Silverlight, MVC and EDM because the prototypes with MVC were nearing a million lines of code, all of our future development is PHP and MySql based. Productivity was Microsoft's biggest benefit over open source, the unique part is with Microsoft's current trend they are closing the gap on their own.

  10. Rick says:

    @Sam I agree MVC usage would be interesting, I read somewhere it wasn't near 5% yet. I assume if MVC was building a strong corporate base Microsoft would be stating it, the quick introduction of the Razor view engine IMHO is a sign they totally missed the mark. Our company recently halted all R and D with Silverlight, MVC and EDM because the prototypes with MVC were nearing a million lines of code, all of our future development is PHP and MySql based. Productivity was Microsoft's biggest benefit over open source, the unique part is with Microsoft's current trend they are closing the gap on their own.

  11. Miguelb says:

    How does this relates with .net 4.0 Parallel processing?

    For instance, for this particular case what would be the advantages of using the await instead of a Parallel.ForEach?

    Also, In the parallel case I can cancel parallel tasks and move on without having to wait for all of them to finish – suppose that I want to cancel the wait if a method call returns -1. Can I do that with await?

  12. Mike Gale says:

    This is a major advance.

    F# has shown the way.

    I might eventually even get the idea to be a standard feature across all the languages I use from time to time.  (Don't hold your breath though!)  I was putting a stub of code into PHP yesterday (to talk to a .NET "web service") and this might have changed my decision about the design!!

  13. Lisa Feigenbaum says:

    Hi All,

    I wanted to make sure everyone is aware of the Async CTP Forum we've set up on MSDN:

    social.msdn.microsoft.com/…/threads

    Please join us there to discuss further questions that you may have on the Async CTP!

    Thanks,

    Lisa Feigenbaum

    Lisa (dot) Feigenbaum (at) microsoft (dot) com

    Visual Studio Community Program Manager

  14. Michael Ferguson says:

    Wow — Async code that is actually readable by a human. :0) Great work.