C# 5.0 Asynchrony – A Simple Intro and A Quick Look at async/await Concepts in the Async CTP

By Anoop Madhusudanan

Recently, in Microsoft PDC 2010, Anders announced the new asynchronous features that’ll be introduced in the next version of C# (5.0?). This post is a quick and simple introduction towards using the async and await keywords. If you want to play with the async/await, you may need to download and install the Async CTP from the MSDN Site..

Let us try some simple ‘working’ code first, then we’ll discuss the concepts involved. Consider the following code, where we start a hotel and call our Cook/Chefs to start cooking various dishes. Each cook will take a random time to cook his dish. See the implementation below.

We used ‘async’ to mark our CookDish as an asynchronous method (The method involves async flow, and can return before it is completed).

We used ‘await’ keyword to inform the compiler to re-wire the method in such a way that (a) the remaining part of the method (after using ‘await’) should be executed only after the task is fished (b) Return to the caller immediately.

To understand the above two points, let us have a look at the output of the above program. When you run this, have a look at the output that you’ll get.

See that each time you call CookDish in the for-loop, the cook will be asked to start his job, and the control is returned to the caller, i.e, the StartHotel method, so that we can ask the next cook to start cooking, with out waiting for the first cook to finish. And each cook will finish cooking based on the delay required for cooking, and the remaining part of CookDish will be executed once the cook finishes cooking. Note: When you actually run this, the console messages after ‘StartHotel called..’ line will appear one by one, because Console.WriteLine(..) part of CookDish will be executed after the delay for each cook.

Also, note that in the Main(..) method, the calling context went past StartHotel call before first cook finished his cooking (hence the message “StartHotel called..” before Chef Finished messages). We’ve a Console.ReadLine in our method so that we won’t end Main automatically before all cooks are done with cooking.

A Minimal look at the concepts

This part is more or less about few basic concepts involved. Let us have a closer look at the usage of async/await, which is pretty simple. Have a look at this informal code.

The async keyword is just for informing the compiler that your method involves asynchronous flow, so that it can be re-wired in such a way that the statements after await SomeTask are executed as a continuation of SomeTask, with out blocking anything.

The re-wiring ensures the context can be returned to the Caller() immediately – So that StuffAfterSomeMethod() in Caller (See above code) can be called with out waiting for SomeTask in SomeMethod.

I want to re-iterate that 'await' is not there for blocking anything as you might think. Technically, it is there for marking a delayed execution of what ever that comes after await. So, what ever that comes after ‘await’ in that method will be executed only after the Task is finished. By using await, you are saying the compiler –"hey dude, re-wire this method so that StuffAfterAwait will be executed as a continuation of SomeTask()" - Now, during compile time, the C# compiler will re-wire your above code to something like this.

//Pseudo code
void SomeMethod()
{
StuffBeforeAwait;
//Note: Pseudo code, just to indicate the logic
When SomeTask is completed
{
//We'll enter this only when SomeTask is completed
//Continue with StuffAfterAwait
//Some way to return the result to current sync context
//NOT by directly returning
result=SomeTask.Result;
StuffAfterAwait(result);
}
//Return the context to the caller with out
//waiting for SomeTask to finish.
}

The above code is just informal/pseudo code that represents how the SomeMethod and SomeTask is re-wired.

The actual implementation involves, the compiler generating code for invoking a GetAwaiter() method on the await’s target. GetAwater inturn returns a TaskAwaiter object, and then the BeginAwait and EndAwait methods of the TaskAwaiter is used to do the Continuation re-wiring - that is similar to what we discussed above.

If you remember, Task class was part of the .NET 4.0 TPL, under the System.Thread.Tasks namespace. See my earlier post Tasks 1-2-3 Why What How. The Async CTP provides a GetAwaiter() extension method for the Task class.

A Task in .NET 4.0 is a simple unit of an asynchronous operation. From .NET 4.0 onwards, it is recommended that you should use Tasks instead of creating your own Thread pool work items. Also, it is recommended that you should avoid creating threads, if you don’t need direct control on a thread’s life time.

Anyway, we’ll discuss more about GetAwaiter, BeginAwait and EndAwait in a later post.

I’m talking about Continuation ‘re-wiring’ a couple of times above. What I really meant is, ‘re-wiring’ a sequence of methods to a Continuation Passing Style. If you want to understand more details about CPS and how it is leveraged to implement async/await under the hoods - the best way is to read all these posts from Eric.

Instead of "returning" values as in the more familiar direct style, a function written in continuation-passing style (CPS) takes an explicit "continuation" argument.