How Do I Think About Async Code?!
Increasingly essential to writing responsive applications, asynchronous code is becoming more and more popular. Unfortunately, asynchronous programming adds an additional level of complexity to your code. As a result, understanding how this code even works can be tough no matter your experience level. Whether you’re new to it or you just want a refresher, here is an intro to the world of asynchronous code!
What is asynchronous code?
Asynchronous (async) programming lets you execute a block of code without stopping (or blocking) the entire thread where the action is being executed. A common myth about async code is that it improves performance, which isn’t necessarily true. Instead, the major perk of async programming is that it increases the number of tasks (throughput) that can be executed concurrently without having to block the thread where these actions are taking place.
You may think async code seems a little like multithreaded code. After all, many methods could be executing at the same time in both. In reality, async programming can be used together with singular or multithreaded applications. This means you can have a single-threaded async program, where one thread can run concurrent tasks. Conversely, you can also have a multi-threaded async application, where multiple threads can each run multiple concurrent tasks.
Why should I use async code? Example please!
To use an analogy to demonstrate async programming, consider the action of baking a cake. This action will be represented by a thread that is executing several steps (or tasks), as illustrated in code below. This code is serviceable, and you will still have a yummy cake once the method is done executing. However, since all the code is synchronous, each line will run sequentially. In other words, you will be standing completely still while waiting for the oven to finish preheating. You could be making the batter for your cake in the meantime!
In real life, you typically want to multitask by making the batter while the oven preheats or making the icing while the cake is baking. Doing this increases your productivity and allows you to bake the cake much faster. This is where asynchronous code comes in handy! By making our existing code asynchronous, we can perform more actions to pass the time even while we are awaiting a task like baking the cake in the oven to complete. To do this, we modified our code to include a new function called PassTheTime. This code saves a task’s state, starts running another synchronous or asynchronous function, and retrieves the saved task’s value when it’s actually needed.
When compared to the synchronous MakeCake method that lacks a PassTheTime function call, MakeCakeAsync manages to complete more tasks without blocking the thread and shortens the time it takes to execute the whole method.
How do I write async code in .NET?
Thankfully, C# makes it a “piece of cake” to write asynchronous code with the Task type and the await and async keywords. The Task type tells the caller about the eventual return value type. It also indicates that other actions can execute while the caller method is being processed. The async keyword enables the await keyword, which lets the compiler know that we’ll need the return value of the function, but not right away. As a result, we don’t need to block the call and can continue running other tasks until the awaited value is needed. An async method will initially run synchronously until it hits an await keyword. This is when the asynchronous execution will begin.
I just learned about async code! Now what?
While using async code to bake a cake is great, there are plenty of other real-life applications to use asynchronous code. Two of the most common examples include:
- Programs using HTTP requests – Depending on the request, HTTP calls can take a long time to fully process. Using async code can let you perform other work while waiting for the server to respond.
- Programs using UI elements – WPF apps or any apps using buttons, textboxes, and other UX assets lend themselves well to async implementation. For instance, a WPF app taking in a file to be parsed may take a while. By making this action async, you can still interact with the UI without having the app completely freeze as you wait for the function to complete.
Now that you know the basics of asynchronous programming, it’s time to improve on it! There are a lot of secret do’s and don’ts when writing solid async code. For a great resource that explores these tips and tricks, check out David Fowler’s post on async programming.
Like all code, there will come a time where you’ll need to diagnose bugs in your async program. To learn how to debug your async code in Visual Studio, tune in for an upcoming blog post…
Side note: And no, I did not use the cake analogy just because I’ve been doing a lot of baking recently. 😉