This chapter covers
- Using Task and Task<T> to check whether an operation has completed
- Using Task and Task<T> to notify your code when the operation has completed
- Using Task and Task<T> in synchronous code
- How async/await works
In the previous chapter, we saw how the compiler can transform our code to add language features. In this chapter, we’ll learn how it applies to async/await.
async/await is a feature that lets us write asynchronous code as if it were normal synchronous code. With asynchronous programming, when we perform an operation that would normally make the CPU wait (usually for data to arrive from some device—for example, reading a file), instead of waiting, we just do something else. Making asynchronous code look like normal code is kind of a big deal because traditionally, you had to divide each sequence of operations into small parts (breaking at each asynchronous operation) and call the right part at the right time. Unsurprisingly, this makes the code confusing to write.
3.1 Asynchronous code complexity
Figure 3.1 Logical flow versus code running asynchronously
![](https://drek4537l1klr.cloudfront.net/dobovizki/Figures/CH03_F01_Dobovizki.png)
Clearly, the left side describing the logical flow is simple, linear, and easy to understand, while the right side that describes how the asynchronous version is running is none of those things (it’s also very difficult to debug).