Based on the recent comments on this article, I made some changes to it. Thank you for your attention.
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
End methods. You are responsible to call
Begin method of that operation and somewhere else pool for the completion/cancellation status and finally call
End method 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:
doTheJob() is called (this is our initial step).
- The function executes synchronously until it reaches the
await keyword in
doSomethingASync() where the asynchronous task is returned.
- 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
- The execution continues in the "anounymous-task" function until it reaches to “
return” and continues in the "
doTheJob()" synchronously up to “
- 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
async way. 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
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
- Your code is more readable, understandable and thus debug able.
What is the Difference with ContinueWith() in .NET 4.0?
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
.Result on a faulted
Task inside of
ContinueWith will re-throw
await will try to keep you on the same thread if they can
So upgrade to .NET 4.5 and use
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?
- 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.
- 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)
- 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".
- But, "
Context a" is blocked before!
There are two approaches for that:
- Never use any kind of blocking waits and instead use
When functions to wait for a task to be completed and continue after completion.
- Allow wrapped content to be executed in "
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!
Sometimes, it is really unnecessary to force execution continues in the caller context, for example it is an I/O operation which can be done in a background thread in other contexts so it is a good idea to use
ConfigureAwait(false) for those cases.
How Is It Possible to Wrap Traditional IAsyncResult Pattern into C# 5 Task?
You may be wondering what if I want to use an
IAsyncResult pair functions which are not provided in the new
The APM pattern was introduced by having
EndOperation pair functions. The
async operation is started prior to a
Begin method call and the result is accessible according to an
End method call once the operation is done, otherwise you would stock in a waited lock for the
async operation to be finished.
Most of the .NET APIs are implemented in the new TAP pattern and you can recognize them easily according to this naming pattern from MSDN:
"Asynchronous methods in TAP include the Async suffix after the operation name; for example, GetAsync for a get operation. If you're adding a TAP method to a class that already contains that method name with the Async suffix, use the suffix TaskAsync instead. For example, if the class already has a GetAsync method, use the name GetTaskAsync".
So if you want to extend an
IAsyncResult pattern and replace them with a single TAP function call, you can use
Task.Factory.FromAsync to create your new behavior over those "
Begin" and "
End" method calls.
"FromAsync Creates a Task that represents a pair of begin and end methods that conform to the Asynchronous Programming Model pattern"
static void Main(string args)
Task<string> t = GetFileStringAsync(file_path);
Console.WriteLine(t.Result.Substring(0, Math.Min(500, t.Result.Length)));
catch (AggregateException ae)
const int MAX_FILE_SIZE = 14000000;
public static Task<string> GetFileStringAsync(string path)
FileInfo fi = new FileInfo(path);
byte data = null;
data = new byte[fi.Length];
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read,
FileShare.Read, data.Length, true);
Task<int> task = Task<int>.Factory.FromAsync(fs.BeginRead, fs.EndRead,
data, 0, data.Length, null);
return task.ContinueWith((antecedent) =>
if (antecedent.Result < data.Length)
Array.Resize(ref data, antecedent.Result);
return new UTF8Encoding().GetString(data);
More to Know
- Do not get confused by the returning type of any
async function. When you call it using
await keyword, it can be considered like a normal function call.
- If you want to use
await keyword, your function has to be defined with
- If you don't call
await inside of your
async function, your
async function actually executes synchronously.
Task.Delay() instead of
- If you are developing a library or you are trying to use
await in ASP.NET for example, do not forget to call
ConfigureAwait(false) otherwise you definitely may introduce an unwanted deadlock.
And one more thing, if you need to have different
await calls which are not dependent on each other (assume them as independent I/O operations), it would be a good idea to
await for them all at once instead of awaiting them one-by-one:
int a = await doSomethingASync(10);
int b = await doSomethingASync(250);
int c = await doSomethingASync(670);
Total execution time would be 3+2+5 seconds which is 10 seconds. But these operations are not dependent to each other so the below code would have better performance and lower execution time:
Task<int> jobs = new Task<int>;
jobs = doSomethingASync(10);
jobs = doSomethingASync(250);
jobs = doSomethingASync(670);
In this pattern, the total execution time would be around 5 seconds (the most time consuming operation) and the rest would take advantage of asynchronous operation.
Point of Interest
In some cases, the amount of work required to complete the operation is less than the amount of work required to launch the operation asynchronously. Reading from a stream where the read operation can be satisfied by data that is already buffered in memory is an example of such a scenario. In such cases, the operation may complete synchronously, and may return a task that has already been completed.
Just keep it in mind.