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

By Anoop Madhusudanan

Vote on HN

image 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..

In short, “async” modifier marks method or lambda as asynchronous. “await” operator yields control until awaited task completes.

Writing some actual Code

Might be helpful if you read Tasks 1-2-3 Why What How before this, if you are not familiar with Tasks.

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.

        

        static Random rnd = new Random();

        static void Main(string[] args)
        {
            //Do some other heavy duty background task in this thread
            StartHotel();
            Console.WriteLine("StartHotel called..");
            Console.ReadLine();

        }

        static void StartHotel()
        {
            Console.WriteLine("Starting Hotel..");

            for (int i = 0; i < 10; i++)
            {
                string name = "Chef" + i;
                CookDish(name, "Dish"+i);
                Console.WriteLine("Asked {0} to start cooking at {1}", name, DateTime.Now.ToString());
            }
        }

        static async void CookDish(string chefName, string dish) 
        {
            //Induce a random delay 
            int delay = rnd.Next(1000, 4000);
            //Cook is cooking - Task
            await TaskEx.Delay(delay);
            //Write the result - StuffAfterAwait
            Console.WriteLine( "Chef {0} Finished at {1}",chefName,DateTime.Now.ToString());
        }

See the usage of ‘async’ and ‘await’ keywords.

  • 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.

image

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.

void Caller() 
{ 
  SomeMethod(); 
  StuffAfterSomeMethod(); 
} 

//Mark a method as async 
async void SomeMethod() 
{ 
   StuffBeforeAwait(); 

   //Ask compiler to re-wire StuffAfterAwait as a continuation, 
   //and return execution point to the Caller immediately 
   var result=await SomeTask(); //Remember cooking part 

   StuffAfterAwait(result); 
}

There are two interesting aspects here.

  • 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.

So, hope you’ve a better idea of async/await now. Happy Coding!!

© 2012. All Rights Reserved. Amazedsaint.com