You are previewing Async in C# 5.0.

Async in C# 5.0

Cover of Async in C# 5.0 by Alex Davies Published by O'Reilly Media, Inc.
  1. Async in C# 5.0
  2. SPECIAL OFFER: Upgrade this ebook with O’Reilly
  3. Preface
    1. Intended Audience
    2. How to Read This Book
    3. Conventions Used in This Book
    4. Using Code Examples
    5. Safari® Books Online
    6. How to Contact Us
    7. Acknowledgments
  4. 1. Introduction
    1. Asynchronous Programming
    2. What’s So Great About Asynchronous Code?
    3. What Is Async?
    4. What Async Does
    5. Async Doesn’t Solve Everything
  5. 2. Why Programs Need to Be Asynchronous
    1. Desktop User Interface Applications
      1. An Analogy: The Cafe
    2. Web Application Server Code
      1. Another Analogy: The Restaurant Kitchen
    3. Silverlight, Windows Phone, and Windows 8
    4. Parallel Code
    5. An Example
  6. 3. Writing Asynchronous Code Manually
    1. Some Asynchronous Patterns Used in .NET
    2. The Simplest Asynchronous Pattern
    3. An Introduction to Task
    4. The Problem with Manual Asynchrony
    5. Converting the Example to Use Manual Asynchronous Code
  7. 4. Writing Async Methods
    1. Converting the Favicon Example to Async
    2. Task and await
    3. Async Method Return Types
    4. Async, Method Signatures, and Interfaces
    5. The return Statement in Async Methods
    6. Async Methods Are Contagious
    7. Async Anonymous Delegates and Lambdas
  8. 5. What await Actually Does
    1. Hibernating and Resuming a Method
    2. The State of the Method
    3. Context
    4. Where await Can’t Be Used
      1. catch and finally Blocks
      2. lock Blocks
      3. LINQ Query Expressions
      4. Unsafe Code
    5. Exception Capture
    6. Async Methods Are Synchronous Until Needed
  9. 6. The Task-Based Asynchronous Pattern
    1. What the TAP Specifies
    2. Using Task for Compute-Intensive Operations
    3. Creating a Puppet Task
    4. Interacting with Old Asynchronous Patterns
    5. Cold and Hot Tasks
    6. Up-Front Work
  10. 7. Utilities for Async Code
    1. Delaying for a Period of Time
    2. Waiting for a Collection of Tasks
    3. Waiting for Any One Task from a Collection
    4. Creating Your Own Combinators
    5. Cancelling Asynchronous Operations
    6. Returning Progress During an Asynchronous Operation
  11. 8. Which Thread Runs My Code?
    1. Before the First await
    2. During the Asynchronous Operation
    3. SynchronizationContext in Detail
    4. await and SynchronizationContext
    5. The Lifecycle of an Async Operation
    6. Choosing Not to Use SynchronizationContext
    7. Interacting with Synchronous Code
  12. 9. Exceptions in Async Code
    1. Exceptions in Async Task-Returning Methods
    2. Unobserved Exceptions
    3. Exceptions in Async void Methods
    4. Fire and Forget
    5. AggregateException and WhenAll
    6. Throwing Exceptions Synchronously
    7. finally in Async Methods
  13. 10. Parallelism Using Async
    1. await and locks
    2. Actors
    3. Using Actors in C#
    4. Task Parallel Library Dataflow
  14. 11. Unit Testing Async Code
    1. The Problem with Unit Testing in Async
    2. Writing Working Async Tests Manually
    3. Using Unit Test Framework Support
  15. 12. Async in ASP.NET Applications
    1. Advantages of Asynchronous Web Server Code
    2. Using Async in ASP.NET MVC 4
    3. Using Async in Older Versions of ASP.NET MVC
    4. Using Async in ASP.NET Web Forms
  16. 13. Async in WinRT Applications
    1. What Is WinRT?
    2. IAsyncAction and IAsyncOperation<T>
    3. Cancellation
    4. Progress
    5. Providing Asynchronous Methods in a WinRT Component
  17. 14. The Async Compiler Transform—in Depth
    1. The stub Method
    2. The State Machine Struct
    3. The MoveNext Method
      1. Your Code
      2. Transforming Returns to Completions
      3. Get to the Right Place in the Method
      4. Pausing the Method for the await
      5. Resuming after the Await
      6. Completing Synchronously
      7. Catching Exceptions
      8. More Complicated Code
    4. Writing Custom Awaitable Types
    5. Interacting with the Debugger
  18. 15. The Performance of Async Code
    1. Measuring Async Overhead
    2. Async Versus Blocking for a Long-Running Operation
    3. Optimizing Async Code for a Long-Running Operation
    4. Async Versus Manual Asynchronous Code
    5. Async Versus Blocking Without a Long-Running Operation
    6. Optimizing Async Code Without a Long-Running Operation
    7. Async Performance Summary
  19. About the Author
  20. SPECIAL OFFER: Upgrade this ebook with O’Reilly
  21. Copyright
O'Reilly logo

Chapter 1. Introduction

Let’s start with a high-level introduction to the async feature in C# 5.0, and what it means for you.

Asynchronous Programming

Code is asynchronous if it starts some long-running operation, but then doesn’t wait while it’s happening. In this way, it is the opposite of blocking code, which sits there, doing nothing, during an operation.

These long-running operations include:

  • Network requests

  • Disk accesses

  • Delays for a length of time

The distinction is all about the thread that’s running the code. In all widely used programming languages, your code runs inside an operating system thread. If that thread continues to do other things while the long-running operation is happening, your code is asynchronous. If the thread is still in your code, but isn’t doing any work, it is blocked, and you’ve written blocking code.

Note

Of course, there is a third strategy for waiting for long-running operations, called polling, where you repeatedly ask whether the job is complete. While it has its place for very short operations, it’s usually a bad idea.

You’ve probably used asynchronous code before in your work. If you’ve ever started a new thread, or used the ThreadPool, that was asynchronous programming, because the thread you did it on is free to continue with other things. If you’ve ever made a web page that a user can access another web page from, that was asynchronous, because there’s no thread on the web server waiting for the user’s input. That may seem completely obvious, but think about writing a console app that requests the user’s input using Console.ReadLine(), and you might be able to imagine an alternative blocking design for the web. It may have been a terrible design, yes, but it would have been possible.

The difficulty with asynchronous code is that, quite often, you want to know when an operation is finished. Then you want to do something else. This is trivially easy to do in blocking code: you can just write another line of code below the long-running call. In the asynchronous world, however, this doesn’t work, because your next line will almost certainly run before the asynchronous operation has finished.

To solve this, we have invented a menagerie of patterns to run some code after a background operation completes:

  • Inserting the code into the background operation, after the main body of the operation

  • Signing up to an event that fires on completion

  • Passing a delegate or lambda to execute after completion (a callback)

If that next operation needs to execute on a particular thread (for example, a WinForms or WPF UI thread), you also need to deal with queuing the operation on that thread. It’s all very messy.

What’s So Great About Asynchronous Code?

Asynchronous code frees up the thread it was started on. That’s really good for lots of reasons. For one thing, threads take up resources on your machine, and using fewer resources is always good. Often, there’s only one thread that’s able to do a certain job, like the UI thread, and if you don’t release it quickly, your app becomes unresponsive. We’ll talk more about these reasons in the next chapter.

The biggest reason that I’m excited about async is the opportunity it provides to take advantage of parallel computing. Async makes it reasonable to structure your program in new ways, with much finer-grain parallelism, without the code becoming complicated and unmaintainable. Chapter 10 will explore this possibility.

What Is Async?

In version 5.0 of the C# language, the compiler team at Microsoft has added a powerful new feature.

It comes in the form of two new keywords:

  • async

  • await

It also relies on some additions and changes to the .NET Framework 4.5 that power it and make it useful.

Note

Async is a feature of the C# compiler that couldn’t have been implemented by a library. It performs a transformation on your source code, in much the same way that lambdas and iterators do in earlier versions of C#.

The feature makes asynchronous programming a lot easier by eliminating the need for complex patterns that were necessary in previous versions of C#. With it, we can reasonably write entire programs in an asynchronous style.

Throughout the book, I’m going to use the term asynchronous to refer to the general style of programming that is made easier by the C# feature called async. Asynchronous programming has always been possible in C#, but it involved a lot of manual work from the programmer.

What Async Does

The async feature is a way to express what to do after a long-running operation is completed, one that’s easy to read but behaves asynchronously.

An async method is transformed by the compiler to make asynchronous code look very similar to its blocking equivalent. Here is a simple blocking method that downloads a web page.

private void DumpWebPage(string uri)
{
    WebClient webClient = new WebClient();
    string page = webClient.DownloadString(uri);
    Console.WriteLine(page);
}

And here is the equivalent method using async.

private async void DumpWebPageAsync(string uri)
{
    WebClient webClient = new WebClient();
    string page = await webClient.DownloadStringTaskAsync(uri);
    Console.WriteLine(page);
}

They look remarkably similar. But under the hood, they are very different.

The method is marked async. This is required for any methods that use the await keyword. We’ve also added the suffix Async to the name of the method, to follow convention.

The interesting bit is the await keyword. When the compiler sees this, it chops the method up. Exactly what it does is pretty complicated, so for now I will introduce a false construct that I find useful as a way to think about simple cases.

  1. Everything after await is moved into a separate method.

  2. We use a new version of DownloadString called DownloadStringTaskAsync. It does the same as the original, but is asynchronous.

  3. That means we can give it the new second method, which it will call when it finishes. We do this using some magic that I’ll tell you about later.

  4. When the download is done, it will call us back with the downloaded string—which we can use, in this case, to write to the console.

private void DumpWebPageAsync(string uri)
{
    WebClient webClient = new WebClient();
    webClient.DownloadStringTaskAsync(uri) <- magic(SecondHalf);
}

private void SecondHalf(string awaitedResult)
{
    string page = awaitedResult;
    Console.WriteLine(page);
}

What happens to the calling thread when it runs this code? When it reaches the call to DownloadStringTaskAsync, the download gets started. But not in this thread. In this thread, we reach the end of the method and return. What the thread does next is up to our caller. If it is a UI thread, it will go back to processing user actions. Otherwise, its resources might be released. That means we’ve written asynchronous code!

Async Doesn’t Solve Everything

The async feature has deliberately been designed to look as similar to blocking code as possible. We can deal with long-running or remote operations almost as if they were local and fast, but keep the performance benefits of calling them asynchronously.

However, it’s not designed to let you forget that there are background operations and callbacks happening. You need to be careful with lots of things that behave differently when you use async, including:

  • Exceptions and try..catch...finally blocks

  • Return values of methods

  • Threads and context

  • Performance

Without understanding what’s really happening, your program will fail in surprising ways, and you won’t understand the error messages or the debugger to be able to fix it.

The best content for your career. Discover unlimited learning on demand for around $1/day.