async/await – What You Should Know

async/await – What You Should Know


Sometimes, we use new technologies while we are not aware of the bottlenecks and weird parts of that technology which eventually might trap us in bad situations like deadlocks which may be really hard to track. What exactly happens in Task-based Asynchronous Pattern (TAP), what are the improvements since .NET 4.0, how may we introduce a deadlock and how to prevent it?

Consider somewhere in your code, you need to do something asynchronous, what are the different ways to do it? Here are some of the patterns:

  • Asynchronous Programming Model (APM): This model is also called IAsyncResult pattern where asynchronous operations require Begin and End methods. You are responsible to call Begin method of that operation and somewhere else pool for the completion/cancellation status and finally call Endmethod to retrieve the actual result of that operation. It is possible to define a callback function so when the operation is done, your callback function is called or you can block your execution until the result is ready. This pattern is not recommended in the new development, please keep it in mind.
  • Event-based Asynchronous Pattern (EAP): This type of async programming was introduced in .NET 2.0 and is not recommended in the new development. In this model, you need to have event handler delegate types and EventArg-derived types and in some scenarios, a worker thread to handle the async job and when it is finished, signal the parent about completion of the job.
  • TAP model: We will discuss it in this article.

In the above patterns, you may easily end-up with lots of worker threads that are consuming your resources or in the worse case, you may face a hard time to manage sequence of events and execution process.

But, what about a way to somehow code synchronous but execute it asynchronous? Just leave the hard part to the compiler to make it happen for us?


What Does async/await Exactly Do?

Whenever you declare or see a function as async, it means that this function is wait able and you can call it asynchronously using await keyword. As soon as compiler sees the await keyword, it does the magic for us and immediately returns to the calling function without the need to wait for the job to be completed and the execution would be able to continue its job.

It sounds great, isn’t it?

Here is the explanation:

  1. The doTheJob() is called (this is our initial step).
  2. The function executes synchronously until it reaches the await keyword in doSomethingASync() where the asynchronous task is returned.
  3. A new Task is created on-the-fly and starts to execute asynchronously and the continuation is scheduled at this point to run the remainder of the code in doTheJob().
  4. The execution continues in the “anounymous-task” function until it reaches to “return” and continues in the “doTheJob()” synchronously up to “return”.
  5. The execution of this function is done too and the Task which is returned by doTheJob() is completed and any possible continuations registered with it may now be scheduled.

It seems a little weird but it is actually simple to understand. as you may have already noticed, although your code seems to be very similar to synchronous programming, but in fact it is going to be executed in an asyncway. You can simply await for a “time consuming” task and leave it there to be completed and schedule your execution once it is done!

What is the Benefit?

  • Your synchronous style of coding would be executed asynchronously , that’s the magic (of course with the help of async/await and Task.Run in this article for example)
  • You won’t be worried anymore about lots of event pooling/checking, thread synchronizations and tough situations you experienced before just to handle multi-threaded asynchronous approaches.
    Of course, you still have to understand asynchronous programming and how to synchronous any shared state, which means there’s still the potential for race conditions, deadlocks, starvation, etc. as you may find in this article. (See the “What is the ConfigureAwait() for”)
  • Your code is more readable, understandable and thus debug able.

What is the Difference with ContinueWith() in .NET 4.0?

Actually, the async/await is a replacement of their successor “ContinueWith()” which was introduced in NET 4.0. Each approach has its pros and cons.

  • ContinueWith is ignorance of sync context
  • ContinueWith pushes you to a new thread, even if the parent is already complete
  • Access .Result on a faulted Task inside of ContinueWith will re-throw
  • Async/await will try to keep you on the same thread if they can

So upgrade to .NET 4.5 and use async and await

What is the ConfigureAwait() for?

It was introduced since .NET 4.5 because of some deadlock situation which may happen in accordance with a bad code structure. Consider the following diagram:

What happened? Did you get it?

  1. When you awaitened in Fn2(), it actually moved the f() execution into another context with its thread pool and the rest of Fn2() was wrapped to be executed after the f() call is done.
  2. The execution control returned to Fn1() and continued until it reached out to a Blocking wait. Here is the point. (You actually blocked “Context a” execution process for another async operation to be completed)
  3. As soon as async operation in “Context b” is completed, it tries to get access to “Context a” just to inform it that “execution is done, let’s continue with the wrapped part”.
  4. But, “Context a” is blocked before!
  5. Deadlock!

There are two approaches for that:

  • Never use any kind of blocking waits and instead use WhenAll or When functions to wait for a task to be completed and continue after completion.
  • Allow wrapped content to be executed in “Context b“.

For the second approach, you need to somehow configure the await keyword to be aware of that! So you need to call ConfigureAwait(false) so the compiler would know that the wrapped content must be executed in the async context and there is no need to return back to calling context just to continue wrapped content!

continue reading in Codeproject :

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.