In one of my previous posts, I discussed about the synchronous and asynchronous programming model. We saw in details that how does it work in single and multi-threaded mode. This post is extension of that post and here we are going to discuss the two relatively new keyword async and await and how does that actually work. I got many questions around this so sharing it in details here. If you are not very clear about how synchronous and asynchronous programming works and how does it work in single and multi-threaded scenario then refer my previous post mentioned below.
Concurrency vs Multi-threading vs Asynchronous Programming : Explained
By now you all have clear idea about the asynchronous programming and why it is so important. Without the power of asynchronous programming, you cannot properly utilize of your resources. Also as now focus is more on user experience, asynchronous programming allows us write very user friendly, intuitive application. Earlier, writing the asynchronous program was bit cumbersome when we used to work with APM (Asynchronous Programming Model) or EAP (Event-based Asynchronous Pattern) model. Debugging and finding issues in asynchronous code was another major challenge. Microsoft understood the issue and came up with two new keywords async and await in .NET 4.5 (C# 5.0) which made the writing the asynchronous code very easy.
Writing Asynchronous code with async and await is almost similar to writing synchronous code. All the other required basic activities like context switching, maintaining the thread state etc are taken care by the .NET framework for us. These keywords are provided on top of Task (TPL- Task Parallel Library) that got introduced in .NET 4.0. Writing asynchronous activities with these keywords are highly optimized, performance oriented and make the best use of TPL. We will understand that in detail in this post.
First let’s see some basics about using async and await in a program.
- async and/or await keyword cannot work in isolation. Both are these required in a peace of asynchronous snippet.
- The return type of the method should be async Task (async void Task) or async Task<T> where T is the type of object returned by the method, although async void is not recommended.
- The asynchronous method returns a Task which runs in a different thread (most probably) and one should use await keyword while reading the output.
- If the thread completes the task then one gets the result right away else control gets returned and move forward once it gets completed.
- Any method that supports async model, appended with async though as a standard it is not a must have rule.
Many classes like HTTPClient, SyndicationClient, StreamWriter, StreamReader, Entity Framework and WCF provides asynchronous methods which can be used to leverage the asynchronous programming. With each release Microsoft adds capability with more operations. Lets see an example.
First let’s us write a very simple code.
As discussed, the above async method has a return type of async Task<int>. Refer line number 10, here we have called ReadAsync method of filestream which returns Task<int>. We have used await keyword (line number 15) which returns the length if task completed else wait till it completed and return the same.
Now lets understand the complete flow
Here ReadFileAsync is called from any method then lets see how does the complete flow works based on the number provided.
- We created a instance of FileStream and call ReadAsync method.
- As soon as ReadAsync gets called, File reading started asynchronously and the .NET framework returns the control the caller ReadFileAsync. ReadAsync returns a Task where TResult is int.
- readTask represents the task that is returned by ReadAsync. Task (readTask) is a “hot” task (running Task) probably on different thread (Represented T2 in.pic)
- The current thread T1 continues and do some other activity and reaches to await.
- Here if readTask gets completed then it gets the length and continues on same thread. But say it is not completed so thread wont be blocked. Else it would returned to the caller of ReadFileAsync and continue there.
- Once the readTask completes, it would picked up by same or different thread (T3) to continue which will get the result from Task and assigned to length.
- length would be returned from the ReadFileAsync .
Note – I have used three colors to represent that the above code that can run on three different threads (T1, T2, T3) for better understanding. But the .net run-time behind the scene tries to minimize the number thread to be used. Sometimes it runs in single threaded asynchronous mode (as discussed in my earlier post).
I hope it clarifies the working of async and await operators. Do share your comments/Feedback.
Thank you very much. This clarifies me.
What would be the impact of putting the await on line 10?
If you put the await at line 10 then ReadAsync would be fired asynchronously as explained and the control would be returned back to the caller from there itself which is happening at line 15 in the post.
Please let me know if that clarifies or have any further question