Asynchronous programming in C# 5

One of the more radical design decisions in the forthcoming Windows Runtime is that no API may, even potentially, take more than 50 milliseconds to complete. Operations that could take longer than that will instead have a ‘kick off this operation’ API that returns immediately without waiting for the result of the operation. The reason for this is that Microsoft want Windows 8 Metro applications to be ‘fast and fluid’ — with the immediacy of touch-based UIs, even small hiccups in responsiveness are more obvious and jarring than with a mouse or keyboard. From a UI point of view, therefore, this is a very helpful design policy.

From a developer point of view, though, it makes life a bit tricky. When we call read from a file or make a WCF service call, it’s usually because we want to do something with the result. When the result is guaranteed to be available when the file read or WCF service API returns, we can write our code in a top-to-bottom form which is easy to understand and easy to reason about.

string url = ReadUrlFromFile(filename);
string contentOfUrl = HttpGetFromUrl(url);
MessageBox.Show(contentOfUrl);

APIs like this are called synchronous or blocking. Synchronous APIs are easy to use and understand, but your entire program (well, the current thread) is unresponsive while you’re inside one. The API can’t return control to your code to do other tasks, because it can’t deliver the results yet.

The style of having a ‘kick off’ API which returns immediately is called asynchronous or non-blocking. Programming with asynchronous APIs is more difficult, because you can’t just return the results into a variable and keep going:

string url = BeginReadUrlFromFile(filename);  // Won't work -- file read hasn't completed when BeginRead returns
string contentOfUrl = BeginHttpGetFromUrl(url);  // Ditto
MessageBox.Show(contentOfUrl);

Instead, you have to put the code that uses the results into a callback, which the slow operation will invoke when it’s good and ready:

BeginReadUrlFromFile(filename, url => {
    BeginHttpGetFromUrl(url, contentOfUrl => {
      MessageBox.Show(contentOfUrl);
    });
  });

Even a simplified example like this looks pretty ugly. In real asynchronous code, with more operations being composed, more complex callbacks, conditional logic, early exits and error handling, well, it gets pretty ugly. And the asynchronous APIs in the real .NET Framework are uglier still, with IAsyncResult objects and paired EndXxx method calls cluttering up the shop.

And yet this is the way our users would like us to work, and the way we will have to work if we want to target the Windows Runtime.

The old solution: use F#

The brainy folk behind F# figured out a way to get the best of both worlds. F# includes a feature called asynchronous workflows, which are blocks of code introduced by async. In an asynchronous workflow, you can call asynchronous methods using a syntax that looks just like synchronous code:

async {
  let! url = BeginReadUrlFromFile filename
  let! contentOfUrl = BeginHttpGetFromUrl url
  MessageBox.Show(contentOfUrl)
}

The F# compiler automatically converts this nice readable, understandable code into the ghastly callback-style equivalent, thus giving you the ease of use of top-to-bottom coding with the responsive behaviour of asynchronous calls.

The new solution: use C# 5

Now, the equally brainy folk behind C# have implemented the same feature in C#. The next version of C#, which is included in Visual Studio 11 beta, introduces two new keywords, async and await.

The async keyword simply indicates that a method makes asynchronous calls. This is important for callers to know, because it means the method may return before it finishes — the method can yield back to its caller at any asynchronous call.

The await keyword indicates an asynchronous call where we want to keep writing top-to-bottom logic instead of writing out the callbacks by hand. Here’s how they fit together:

public async void ShowReferencedContent(string filename) {
  string url = await BeginReadFromFile(filename);
  string contentOfUrl = await BeginHttpGetFromUrl(url);
  MessageBox.Show(contentOfUrl);
}

This is much easier to write, read and sanity-check than the callback version, but it’s doing the same thing. (Actually, it’s quite a bit smarter than the callback version, because compilers don’t get bored and skip over error conditions or screw up early exit logic or ignore threading issues.)

What happens when we call this method? The first thing that happens is that BeginReadFromFile gets called, with the provided filename and the compiler-generated callback. BeginReadFromFile returns immediately, but the result isn’t available yet. So rather than assigning the result to the url variable — which is actually part of the callback — the method then exits and returns to the caller! The calling method resumes and keeps running its code, even though the called method hasn’t yet finished.

Then, at some later point, the file system completes the read operation. This means the result is now available, and the runtime schedules the callback. This doesn’t necessarily happen immediately — the exact timing depends on the synchronisation context. The callback runs, binds the url variable to the result of the file operation, and calls BeginHttpGetFromUrl. This also returns immediately, meaning the method exits again.

Finally, the HTTP operation completes and the second callback runs. This binds the contentOfUrl variable and, as in all bad demos, displays a message box with the result.

What if I want to return a value to the caller?

Async methods can exit before they’ve finished. So if an async method wants to return a result, it has to recognise that it might return to the caller before that result is available. For this reason, an async method that returns a value has to have a return type of Task rather than a ‘proper’ value. A Task represents a chunk of work which will eventually deliver a value, so a caller can examine the returned Task to determine when the result becomes available. Here’s how an async method looks when returning a value:

public static async Task<string> GetReferencedContent(string filename)
{
  string url = await BeginReadFromFile(filename);
  string contentOfUrl = await BeginHttpGetFromUrl(url);
  return contentOfUrl;
}

Notice that the return statement takes a string, even though the return type is Task<string>. Again, the compiler takes care of transforming the return statement to produce a Task.

Now a caller can call the GetReferencedContent method and either await on it to the string when it becomes available, or wait on it manually, or poll it for completion — whatever suits the way it intends to use the result.

Async-friendly APIs

If you’re familiar with asynchronous programming in .NET 4 and earlier, you’ll be used to paired Begin and End methods, such as WebRequest.BeginGetResponse and WebRequest.EndGetResponse. These still exist in .NET 4.5, but they don’t work with the await keyword. (Basically because a BeginXxx method requires an explicit method call inside the callback to get the result, and the compiler couldn’t depend on the EndXxx naming convention.) Instead, .NET 4.5 provides new methods which return Task objects. So instead of calling WebRequest.BeginGetResponse, you’ll call WebRequest.GetResponseAsync. Here’s an example where we finally use some real .NET 4.5 async APIs:

private static async Task<string> GetContent(string url)
{
  WebRequest wr = WebRequest.Create(url);
  var response = await wr.GetResponseAsync();
  using (var stm = response.GetResponseStream())
  {
    using (var reader = new StreamReader(stm))
    {
      var content = await reader.ReadToEndAsync();
      return content;
    }
  }
}

Note how similar this looks to the synchronous code using WebRequest.GetResponse() and TextReader.ReadToEnd(). Just stick Async on the end of the API name and stuff an await in front of the call, and you’re good to go!

Tagged as General

14 Responses to “Asynchronous programming in C# 5”

  • Great post Ivan, looking forward to using await with a vengeance!

  • I know it’s a major new feature, but I wish they’d stick closer to the framework numbering system… I’ve been calling this C# 4.5 for a while, and I hate being wrong ;)

  • Thanks Ivan really well explained, this is going to make async code so much more manageable.

  • Reactive extension addresses all this already, sometimes in a non intuitive fashion. So does TPL9which I think is simpler compared to Rx). However this may make async programming more mainstream as the syntax is simpler.

    But the message from Microsoft isnt clear. We have now Reactive, TPL etc and now this; all answering the same type of problem. The message coming out doesnt seem coherent and appears desultory.

  • Ivan – long time reader, first time caller…. Nice post, clearly explained and the good to work in the features heritage but…. Sure the post is an intro, but there seems to be an ongoing over simplification of async programming when discussing async/await.

    In the companies i’ve worked for synchronous programming is still very common, because async programming is hard. It’s hard because the code is scattered, but it’s really hard because your have to deal with UI work where you may or may not have the data. Put another way, your UI is trying to represent a set of time ranges of data. If you are retrieving 3 sets of data A, B and C and these three requests are in flight you may get A back and not B and C.

    Thats no problem if the requests, and what you do with the data are independent. But if their not, you need to co-ordinate these. Or maybe there is another set, D, that your not allowed to request until A and B are back etc. Or some user action should be prevented until A and B are back …

    I often code more complicated UI logic as a state machine – co-ordinating button states and events with data fetches etc. Async calls introduce another “axis” into these state machines – time. The flip side of this async calls (futures/Tasks) makes it easier to delay some of these co-ordination options, but i really haven’t gotten my head around whether this helps.

    And Metro – with it’s forced async, like silverlight, will force more developers down this road. Reactive extensions purport to solve this problem. They talk about composing different event streams – but not really event streams with UI logic other than their dictionary suggest example.

    **If** you have the time later i’d love you to blog your thoughts after using async “in anger”.

    Keep up the great blog.

  • Ajay, I don’t think there’s a great deal of overlap between C# async and Rx. Rx is primarily about a push model for sequences. For example, Rx is a great model for a network server to subscribe to a stream of incoming messages. It’s not a great model for a network client to send a request and act on a response. Sure, you can do it, but it doesn’t gain you much over old-skool callback-based async — you’d write a send call and set up a Rx subscription on the response, which is a callback, not top-to-bottom code. As for async and TPL, async is a language feature which basically makes it easier to work with TPL. I don’t see async and TPL as two solutions for the same problem: I see them as the language and library parts of a single solution.

  • Alister, excellent points. Having async and await in the language removes pain points in the simple case where you are performing a sequence of async operations, but it doesn’t remove the subtlety of coordinating across multiple async operations. In that case, developers still need to design and implement the coordination behaviour. I’d argue that’s not the use case for C# async: the case the C# designers were trying to tackle was the 90% UI case, where the user initiates a network operation or the application needs to save its state without causing the UI to hiccup.

    That said, because async methods return TPL tasks, you can use the TPL combinators to help with this coordination. For example, if you want to do something when both A and B complete, you can use the Task.WhenAll combinator (that is, you would await the result of the Task.WhenAll combinator).

    I guess I would sum it up by saying that async is about asynchronous programming, *not* concurrent programming. Your examples involve concurrency, not just asynchrony. Of course, async programs invite concurrency, but usually of a crude and benign form, like “I kicked off a search for B while my search for A was in progress” — the developer just has to decide whether to go for ‘last one wins’ or be a bit smarter and send the two to different panes or tabs or something.

    Sort of off topic, but have you looked at F# mailbox processors? These allow you to encapsulate some coordination logic by hiding the async processing behind a message-based interface (sort of a la Erlang). I’m not sure how helpful they’d be for the kind of conditional scenarios you describe, but they might be worth a quick look.

  • [...] Asynchronous programming in C# 5 – Ivan Towlson discusses the design requirement for Windows Runtime which aims to keep WinRT based applications responsive by ensuring that there are no synchronous APIs which take longer than 50 milliseconds, and explores the shift to async programming in C#5, looking at its origins in F#. [...]

  • Have used the Task based Wait calls. Would love to know/have the skills to do UI based programming in erlang. Haven’t looked at the F# mailbox processors – although worked with a message based system in the past (fibers, co-operative tasks etc). I’ll investigate. My gut feel is that what makes async different from message based systems is that it’s UI based, windows needs to access it’s controls from their creating thread, and hence the fundamental state being manipulated must be shared by all the workers. In the message based system i used, and other doco i’ve read about actor based systems they are based around isolating and splitting state.

    I take your point about the async use case – it’s just targeted at making singular async calls easier.

    Maybe i’m addressing not the async keyword but the other part of this post. “One of the more radical design decisions…that **no** API may ” and you make the excellent point that async can “create” concurrency, and we all know concurrency is hard I’ll end by saying i really think UI programming is going to get tricker in Metro, and tricky quickly. Will be interesting to see what impact this has on app robustness. Maybe sometime in the future you’ll see a book “Async Patterns for UIs” or “Application Workflow Navigation based asynchronous UI’s”. It probably won’t be by me because i’ve spent too much time writing opinion based replies to blog posts !

  • That’s a good point. Actors are about isolating concurrent processes, whereas C# async is more about giving language support to a ‘background worker’ kind of pattern. It’s still not clear to me how to tackle your original comment about coordinating multiple background workers, and you’re right that there’s a danger that naive developers will try to use async/await for concurrent programming tasks that are way beyond what it was designed for. Also that they will be deceived by the top-to-bottom flow of async methods into thinking they don’t need to consider cases like ‘user retries while async operation in progress.’ Mystic Ivan predicts many ‘We’ll just disable the UI while a download is in progress’ and ‘!!! Do not press this button more than once !!!’ UIs in our glorious future…

  • [...] big new feature in C# 5 is asynchronous programming support, which I wrote about last week. However, the C# folks have also slipped in a couple of smaller [...]

  • [...] Asynchronous programming in C# 5 [...]

  • [...] in the Web environment where your page is likely to be communicating with network resources, and as C# programmers are learning, language support can make it so much easier! To use Iced CoffeeScript instead of normal [...]

  • Great info :-)

  • Leave a Reply

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top