DEV Community

Cover image for Async and Await and what is it actually doing?
Sumaiya Asif
Sumaiya Asif

Posted on

Async and Await and what is it actually doing?

Ever write a function that calls another function that happens to be asynchronous? Intellisense complains that the function being called is not being awaited. What did you do? Add the keyword await and voila! Your issue was resolved.

But what is your code doing?

No time to ponder on that, create the pull request and wait for your lead to dig into you and hope that they don't ask you to explain the use of await or why you had to mark your function as async. You can't give them the inclination that you don't know what you're doing!

What it's not

Async programming is not parallel programming. It does not mean "thread A go do X" and "thread B go do Z". It means the "thread" that you are using right now, will do all the tasks but in a order that will best optimize performance. A popular example is someone making breakfast. Say you are making eggs and toast. Your first step is to heat up the pan. While the pan is heating up, take the eggs out of the fridge and the bread out of the pantry. Now your pan is hot, break the eggs to start frying. While the eggs are frying, place the bread in the toaster. Your eggs are done. Plate them. Your toast is ready. Plate that too. Done. It took one person, one thread but the tasks were done in a manner where both items would be cooked simultaneously.

Async

Async enables the use of the await keyword in the method. A method marked with an async keyword, executes like any other function until it gets to the line with the await keyword.

Await

Await provides a non-blocking way to start a task. How? Through method control flow. When a task to download a file has been called, the thread does not wait until its completion. It yields control to the calling method to continue work until the result of the file download is needed. The await keyword indicates the point at which the method is suspended and the control has been passed to the calling function if the task has not been completed.

If the awaited async method has been completed, it returns the result stored into a Task object.

Here is a helpful diagram of the control flow:
async control flow

Task Asynchronous Programming (TAP) model

C# uses the Task Asynchronous Programming (TAP) model to provide an abstraction over asynchronous code. This allows us to read and write code in a synchronous fashion while performing asynchronous tasks. The compiler does all the work figuring out when methods need to be suspended and the order of their execution flows. Doing this work without language support would require a lot of code written by the developer that would convolute the intent of the business logic being executed.

The TAP model essentially utilizes Task objects to hold the async method's results, progress, and other information. You can store the result of an async method to an object of type Task. When the result is needed, you can await that Task object to retrieve the result of the async method.

public async Task cookBreakfast() {
    // Start toasting the bread and let me hold onto an object
    // that I can use to retrieve the result later
    Task toastTask = toastBreadAsync();

    Console.log("Frying eggs");

    // I need the result of ToastBreadAsync() now
    await toastTask;
    Console.WriteLine("toast is ready");
}

public async Task toastBreadAsync(){
    Console.WriteLine("Starting on toast");
    await someToastyThings();
    Console.WriteLine("Done Toasting!");
}
Enter fullscreen mode Exit fullscreen mode

The result of the above code execution would look something like this:

"Starting on toast"
"Frying eggs"
"Done Toasting!"
"toast is ready"
Enter fullscreen mode Exit fullscreen mode

Lets walk through this.

  1. cookBreakfast() is called.
  2. toastBreadAsync() is called
  3. "Starting on toast" is printed
  4. someToastyThings() is called and awaited. Yields control to cookBreakfast()
  5. toastBreadAsync() has it's Task stored into toastTask
  6. "Frying eggs" is printed
  7. toastTask is awaited. Control is back to someToastyThings(); Is it done? Lets say it is.
  8. "Done Toasting" is printed
  9. Control comes back to cookBreakfast
  10. "toast is ready" is printed

Sync vs Async

It is important to call out the differences in building asynchronous applications vs synchronous ones specially with the TAP model.

  • You'll note that a synchronous method returns a value when the method is complete. However, an asynchronous method will return a Task immediately and when it eventually completes, it will store the result in the Task.
  • The next is control flow. When a method is awaited and the results of the method are not yet available, the control is yielded to the calling function. On the flip side, with synchronous programming, control will continue to the next line.

Further Reading

I wasn't born with this information. Here are some really good resources to go deeper on the subject.

I hope this helped scratch the surface on asynchronous programming in dotnet. There is a lot more fancy things that can be done when it comes to this topic but having the fundamental understanding of what is happening in your application is the first step.

Go onward with your PRs with confidence!

Latest comments (7)

Collapse
 
zyabxwcd profile image
Akash

'I wasn't born with this information.' haahaha that was good acknowledgement. i often say that to people too

Collapse
 
tariqmezeik profile image
Ti

nice article.

Collapse
 
antonio_begines profile image
Antonio Begines

making the breakfast: best example ever!

Collapse
 
briandesousa1 profile image
Brian De Sousa

Great post! I have used async/await in JavaScript but I'm not sure whether I really knew what was going on until I read this. Thank you!

Collapse
 
chris_bertrand profile image
Chris Bertrand

Great post! Keep them coming! 🙌

Collapse
 
nhwilly profile image
nhwilly

Well done.

Collapse
 
amsmart profile image
Emmanuel Oluwagbemiga Adebiyi (Smart)

This is awesome!