the concept of async \ await

2011/12/29

the concept of async \ await

in this post I will survey the new .NET 4.5 / C# 5 concept of async / await.

async, await, .NET 4.5, C#5, continuation

I will focus on how to understand what is really happens behind the new async / await syntax.

What’s it all about?

the new async / await syntax is using the C# syntactic compiler to generate async operation from code that is looking very much like a synchronous code.

but before we start we should discus the new C# 5  syntax.

the syntax include 2 keywords:

  • async – which is only a marker for async method.
  • await – indicate a callback boundary.
Code Snippet
  1. static async Task Execute()
  2. {
  3.     Console.WriteLine(run on calling thread);
  4.  
  5.     await Task.Factory.StartNew(() => Thread.Sleep(1000));
  6.  
  7.       Console.WriteLine(run on callback thread);
  8. }

so how should we understand what was written in the above code?

actually it is a different way to represent a continuation (you can read more about the continuation concept in here).

the above code is somewhat identical to the following TPL 4 code:

Code Snippet
  1. static Task Execute()
  2. {
  3.     Console.WriteLine(run on calling thread);
  4.     Task t = Task.Factory.StartNew(() => Thread.Sleep(1000));
  5.     return t.ContinueWith (tsk =>
  6.         {
  7.               Console.WriteLine(run on callback thread);
  8.         });
  9. }

the syntactic compiler will translate the code below the await keyword into continuation state machine, which is logically (not technically) identical to the above code.

Point of interest:

you may have been notice that the async method return a Task even though there is no return within the method block.
surveying the TPL 4 code snippet we can understand that the async method will actually return to the caller immediately after the Task.Factory.StartNew start the task and the rest of the code is actually a continuation callback.

what we got back from the async method is a task which represent the async part of the method.

async / await with return value

async / await can represent a continuation of a callback that accept async result.

Code Snippet
  1. static async Task<DateTime> Execute()
  2. {
  3.     DateTime result = await Task.Factory.StartNew(() => DateTime.Now );
  4.  
  5.       return result.AddDays(1);
  6. }

the above code will logically translate to:

Code Snippet
  1. static Task<DateTime> Execute()
  2. {
  3.     Task<DateTime> t = Task.Factory.StartNew(() => DateTime.Now);
  4.     return t.ContinueWith (tsk =>
  5.         {
  6.               return tsk.Result.AddDays(1);
  7.         });
  8. }

you may have notice that the return value (on the left side of the await) was unwrapped (DateTime instead of Task<DateTime>)

Which thread is running?

async, await, .NET 4.5, C#5, continuation

normally when the method doesn’t invoke from the UI thread, everything before the await line will run synchronously on the caller thread.
the Task.Run naturally will be schedule on a different thread and everything under the await will be schedule on different thread then the caller thread, it may be the same thread of the Task.Run or any other ThreadPool thread (when there is only single continuation it will probably be the same thread as Task.Run)

Async and UI

whenever the async method invocation is coming from UI thread (or to be more precise from thread under synchronization context) the continuation return back to the synchronization context thread.

this is quit similar to the following TPL code (.NET 4):

Code Snippet
  1. TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
  2. Task t = Task.Factory.StartNew(() => Trace.WriteLine("in parallel"));
  3. t.ContinueWith(tsk => Trace.WriteLine("UI thread"), scheduler);

or to more legacy code which is using the synchronization context directly:

Code Snippet
  1. Action a = () => Trace.WriteLine("in parallel");
  2. SynchronizationContext sc = SynchronizationContext.Current;
  3. a.BeginInvoke(ar =>
  4.     {
  5.         sc.Post(state => Trace.WriteLine("UI thread"), null);
  6.     }, null);

async / await is aware of the synchronization context of the caller and if any it schedule the await callback on this context.

async, await, .NET 4.5, C#5, continuation

Summary

the syntactic compiler translate the async / await syntax into state machine which handle the continuation flow after parallel operation.

there is much more for that and I will discuss it in future posts.

you can see it performance characteristic on this post.

Shout it

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>