C# async and await: Why Do We Need Them?
Unresponsiveness of an application’s user interface is an issue every computer user has to deal with regularly. It may happen with system tools, with third party software or, sometimes, with your own applications.
There are two main reasons for such behavior. First is a programming error - when an infinite loop or dead lock is introduced because of developer’s mistake. Well known software development practices, such as Test Driven Development and code reviews help to eliminate these type of errors.
Second common reason of UI unresponsiveness is using the UI thread for performing long operations. For example, the following code demonstrates image downloading in button click handler:
On developers’ PC or event in test environment, this method may work as expected – quickly downloading and displaying image. However, when deployed to the real customers, the ButtonClick method may block the UI for seconds to download the image using a slow or limited Internet connection.
An improved version of ButtonClick may use tasks and task continuations to offload potentially long operations off the main thread. But it can also introduce another type of problem. Now the developer needs to think about synchronization with the main thread and in real-world application, when downloaded data may trigger other network requests, the method will require a cascade of tasks and continuations, making code hard to read.
C# 5: async and await
Async and await keywords in C# are intended to help with offloading long IO operations off the UI thread. This next example demonstrates the same ButtonClick method but now it uses the new async model:
The changes are pretty small but now the download operation is executed asynchronously, without blocking UI. Even better, it is implemented without sacrificing code readability and can be extended by adding more async calls using the same linear style.
The async keyword tells the compiler that the new async functionality will be used in the method. I will talk a bit about implementation details in my next post, but for now, it is enough to understand that compiler transforms async methods in some sort of state machine.
The await keyword ensures that nothing happens before the called asynchronous method is finished. Both keywords - async and await - always work together. await without async is not allowed.
The new async model is not limited to .NET framework functions. Developers can create their own async methods for use in application or include in reusable libraries.
The method GetStringAsync above demonstrates another part of the compiler’s magic: the string result is seamlessly wrapped in the task to allow function awaiting. The result is unwrapped and assigned to the local variable by using await.
Windows 8 and async
While the use of the async and await for WinForms, WPF, and console applications is optional, Windows 8 Runtime APIs (WinRT) is fully asynchronous. All operations that potentially may work longer than 50 milliseconds are implemented as async functions. It includes networking, file system access, sensor APIs, and other IO-bound operations. It is almost impossible to create any functional Windows 8 application without using one or another async call and it is very important to understand how the new async model works and how to use it properly.
Getting started with async
If you are a Windows 8 developer, there is a great chance you are already encountered the async functionality, but desktop developers may not be aware of how to apply it. .NET 4.5 introduced multiple new methods designed to use async and await. You can recognize them by the async suffix in the name and return type of Task or Task<T>. For example WebClient provides DownloadDataTaskAsync() method in addition to DownloadData().
If your applications are not yet migrated to.NET 4.5, you still can use the async functionality with help of Async for .NET 4 NuGet package that brings some of async functionality to the previous version of the framework.
Comments
Anonymous
December 18, 2013
Thanks For ArticlesAnonymous
December 18, 2013
Great article!! ThanksAnonymous
December 18, 2013
ThanksAnonymous
December 18, 2013
Thanks for the nice write-up.Anonymous
December 19, 2013
Nice!Anonymous
December 19, 2013
Good write-up. It's also quite relevant - network latency in our ever-evolving mobile, and always-online computer age, will perhaps always be an issue. This makes threading a standard development best practice.Anonymous
December 19, 2013
this article is exactly what I was looking for! :)Anonymous
December 19, 2013
Thank you all for your comments!Anonymous
December 25, 2013
very interesting and usefulAnonymous
March 11, 2014
Nice Article explains the async and await clearly...Anonymous
October 23, 2014
Great WorkAnonymous
November 27, 2014
Great explanation. Thank you.Anonymous
May 02, 2016
The comment has been removed- Anonymous
May 03, 2016
@Dermot,Agreed, it takes time to fully digest async/await concept. Compiler rewrites async method to create a state machine. One step in the state machine will initiate asynchronous operation. When operation is done, it will call a callback (also created by the compiler) to move state machine into the next step and do all the stuff after the await. If your main UI thread is not blocked it will be successfully executed. Of cause, this is a very simplified picture, in reality more magic happening (including capturing the context, creating inner state machines etc.) but it provides a frame how to think about async/await.- Anonymous
May 17, 2016
Thanks Andrei - surely with doing all that work - state machines, context switching etc - it can't be as performant as code written by developers that know what they're doing with 'old style' threading? I read elsewhere that async/await is 'better' because 'expensive' threads are spun up and torn down, but how does it compare with all the automagic work done out of sight? Granted, dealing with UI blocking isn't a scenario where cycles matter so much. In background service architectures though, it feels like I'm surrendering unknown volumes of CPU cycle to save me a little typing.
- Anonymous
- Anonymous