async / await, some reasoning

2012/01/19

no comments

async / await, some reasoning

this post will try to make some reasoning about the .NET 4.5 / C#5 await keyword.

async, await, task, tpl, parallel, c#5, .NET 4.5

I will begin with a quiz.

how long will it take to the following method to produce the 42 value?

Code Snippet
  1. async Task<int> Execute()
  2. {
  3.     await Task.Delay(1000);
  4.     await Task.Delay(1000);
  5.     return 42;
  6. }

you should remember that conceptually the await keyword will translate to a continuation.

the above code can be compare to the following TPL 4 code snippet:

Code Snippet
  1. Task<int> Execute()
  2. {
  3.     Task t1 = Task.Factory.StartNew(
  4.         () => Thread.Sleep(1000));
  5.     Task t2 = t1.ContinueWith(t1_ =>
  6.         {
  7.             Thread.Sleep(1000);
  8.         });
  9.     Task<int> t3 = t2.ContinueWith(t2_ => 42);
  10.     return t3;
  11. }

whatever come after the await will be compile into a continuation closure.

therefore the 42 value will be produce after 2 second.

How can we await for multiple task?

there is couple of way for awaiting on multiple tasks, but the most recommended one is to use Task.WhenAll (you can also use Task.WhenAny to continue after the completion of the first task).

do not confuse the Task.WhenAll with Task.WaitAll, WhenAll is a continuation which happens when all the task come to completion, while WaitAll is a blocking API which will block the execution until all tasks will be completed.

the following snippet demonstrate the Task.WhenAll usage.

Code Snippet
  1. async Task<int> Execute()
  2. {
  3.     Task t1 = Task.Delay(1000);
  4.     Task t2 = Task.Delay(1000);
  5.     await Task.WhenAll(t1, t2);
  6.     return 42;
  7. }

the 42 value will now produce after 1 second.

it is somewhat equals to the following TPL 4 snippet:

Code Snippet
  1. Task<int> Execute()
  2. {
  3.     Task t1 = Task.Factory.StartNew(
  4.         () => Thread.Sleep(1000));
  5.     Task t2 = Task.Factory.StartNew(
  6.         () => Thread.Sleep(1000));
  7.     Task<int> t3 = Task.Factory.ContinueWhenAll(
  8.         new[]{t1, t2}, tsks => 42);
  9.     return t3;
  10. }

to wrap it up let think how long will it take to the following snippet to produce a value.

Code Snippet
  1. async Task<int> Execute()
  2. {
  3.     for (int i = 0; i < 10; i++)
  4.     {
  5.         await Task.Delay(1000);
  6.     }
  7.     return 42;
  8. }

the right answer is 10 seconds, each iteration will result in a continuation closure which will wrap the following iterations.

this can be translate to something like the following snippet (TPL 4).

Code Snippet
  1. Task<int> Execute()
  2. {
  3.     var stateMachine = new StateMachine();
  4.     return stateMachine.OnNext();
  5. }
  6.  
  7. class StateMachine
  8. {
  9.     private int _i;
  10.     private TaskCompletionSource<int> _semanticTask =
  11.         new TaskCompletionSource<int>();
  12.  
  13.     public Task<int> OnNext()
  14.     {
  15.         Interlocked.Increment(ref _i);
  16.  
  17.         Task t = Task.Factory.StartNew(() =>
  18.             Thread.Sleep(1000));
  19.         if (_i <= 10)
  20.             t.ContinueWith(t_ => OnNext());
  21.         else
  22.             _semanticTask.SetResult(42);
  23.  
  24.         return _semanticTask.Task;
  25.     }
  26. }

the execute method will create a state machine which will chain task continuation 10 times and then set the value of 42.
the TaskCompletionSource represent semantics of task (TAP – Task Async Pattern).

TaskCompletionSource does not produce any concurrency (doesn’t attached to any thread), it just present a task which can be project result, exception or cancellation.

the OnNext method immediately return a semantic task which will signal as complete at line 22 (the exit term of the recursion).

Summary

await present a continuation. each time the code is hitting the await it construct a new continuation closure.

Shout it

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published. Required fields are marked *

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>