C# async and await: Why Do We Need Them?

clip_image002Unresponsiveness 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:

clip_image003

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:

clip_image004

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.

clip_image005

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.

clip_image006

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.