次の方法で共有


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.

Comments

  • Anonymous
    December 18, 2013
    Thanks For Articles

  • Anonymous
    December 18, 2013
    Great article!! Thanks

  • Anonymous
    December 18, 2013
    Thanks

  • Anonymous
    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 useful

  • Anonymous
    March 11, 2014
    Nice Article explains the async and await clearly...

  • Anonymous
    October 23, 2014
    Great Work

  • Anonymous
    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.