codejnki / AsyncAwaitExample

A quick example that shows why I've been doing this wrong for years.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

AsyncAwaitExample

I saw a tweet with a link to an article by Sumaiya Asif explaining async and await that made me realize I've been using this pattern all wrong for years.

So I sat down and wrote this out in an attempt to seal this knowledge into my brain.

The Wrong Way

So for years I've been trying to do things with a minimalist approach to the number of lines of code written.

public static async Task CookBreakfastSlow() {
  await FryEggAsync();
  await ToastBreadAsync();
  Console.WriteLine("Breakfast is ready.");
}

On the surface this looks great.

This is short and compact yet suffers from a complete misunderstanding of what awaiting tasks is supposed to do for us.

When the program hits an await statement it stops what it is doing, and waits.

This method does not allow for synchronous and unrelated operations to continue while waiting for the asynchronous work to complete in the background.

You can see this by looking at the output this produces.

Starting egg frying
Frying
Frying
Frying
Frying
Frying
Egg is done
Starting on toast
Toasting
Toasting
Toasting
Toasting
Toasting
Toast done.
Breakfast is ready.

The Right Way

The right way to use this pattern is to create your tasks as early in your execution path as possible, and then wait for them, preferably at the point immediately before you need their results.

public static async Task CookBreakfastFast() {
  Task eggTask = FryEggAsync();
  Task toastTask = ToastBreadAsync();

  await eggTask;
  await toastTask;

  Console.WriteLine("Breakfast is ready");
}

I know what you are thinking, at first glance this is a full on 28.5% explosion in code. We've been told for years that fewer lines is better performing code. But in the async and await world, these two extra lines of code are going to cut our total execution time by 50%.

Our tasks are now going to get executed in the background. They each start doing their work, and then we wait for them.

If we look at the console output we see a massive difference.

Starting egg frying
Frying
Starting on toast
Toasting
Frying
Toasting
Frying
Toasting
Frying
Toasting
Frying
Toasting
Toast done.
Egg is done
Breakfast is ready

Conclusion

The first method, while compact, and in all fairness compiles and works, is lazy. It doesn't allow for squeezing all the performance out of the method that you could possibly get. This may or may not matter--after all, async isn't about raw performance, it's about throughput.

Allowing your brain to step away from a minimalist view of lines of codes will actually allow the compiler to do it's job, and help your program find the quickest path to completion.

About

A quick example that shows why I've been doing this wrong for years.

License:MIT License


Languages

Language:C# 100.0%