DEV Community

Cover image for C# Async Await, Simply
Henrick Tissink
Henrick Tissink

Posted on • Edited on

C# Async Await, Simply

One at a time

Code is executed to achieve a purpose. Usually it's run as a series of steps, eventually leading to a final result. Each of the steps take some time to execute, and running them synchronously, one after the other, can take a significant amount of time.

alt text

Say you're a Doctor of Evil - a Dr. Evil if you will. And you want to run a successful criminal enterprise to take over the world; maybe you're looking to make One Million Dollars... Would it be the most effective way to run all of your plans one after the other?

Running an Evil Empire

alt text

The first thing you'll need, as an evil mastermind, is of course an Evil Lair.

  • Task.Delay(x) gives a logical delay of x milliseconds without blocking the current thread


public static void BuildAnEvilLair()
{
    await Task.Delay(5000);
    Console.WriteLine("Evil Lair Built!");
}


Enter fullscreen mode Exit fullscreen mode

After you build your lair, you're going to need to hire some henchman.



public static void HireSomeHenchman()
{
    await Task.Delay(2000);
    Console.WriteLine("Henchman Hired!");
}


Enter fullscreen mode Exit fullscreen mode

And of course, you'll need to create a mini clone of yourself.



public static void MakeMiniClone()
{
    await Task.Delay(3000);
    Console.WriteLine("Mini Clone Created!");
}


Enter fullscreen mode Exit fullscreen mode

Once all of this is in place, you can start working on your Super Evil Plan!



public static void SuperEvilPlan()
{
    await Task.Delay(4000);
    Console.WriteLine("Super Evil Plan Completed!");
}


Enter fullscreen mode Exit fullscreen mode

And let's not forget threatening world leaders with your Super Evil Plan and ransoming One Million Dollars.

alt text



public static int MakeOneMillionDollars()
{

    await Task.Delay(2000);
    Console.WriteLine("Million Dollars Made!");
    return 1000000;
}


Enter fullscreen mode Exit fullscreen mode

Finally, when everything has been completed, we can achieve World Domination.



public static void WorldDomination()
{
    await Task.Delay(6000);
    Console.WriteLine("World Domination Achieved!");
}


Enter fullscreen mode Exit fullscreen mode

Putting our plan together,



BuildAnEvilLair();
HireSomeHenchman();
MakeMiniClone();
SuperEvilPlan();
var money = MakeOneMillionDollars();
WorldDomination();


Enter fullscreen mode Exit fullscreen mode

which takes 22 000ms (or 22 seconds) synchronously.

All at once

alt text

Many of the steps in such a synchronous plan can be executed in parallel, asynchronously. So how is this done?

First, all the methods will be made asynchronous with the async descriptor, and their executing code will be awaited.

Awaiting asynchronous code, the awaiting code is processed asynchronously, and the code following the await is added as a continuation to the await. The continuation will be run after the code being awaited has run its duration and been successfully executed.



public static async Task BuildAnEvilLair()
{
    await Task.Delay(5000);
    Console.WriteLine("Evil Lair Built!");
}

public static async Task HireSomeHenchman()
{
    await Task.Delay(2000);
    Console.WriteLine("Henchman Hired!");
}

public static async Task MakeMiniClone()
{
    await Task.Delay(3000);
    Console.WriteLine("Mini Clone Created!");
}

public static async Task SuperEvilPlan()
{
    await Task.Delay(4000);
    Console.WriteLine("Super Evil Plan Completed!");
}

public static async Task<int> MakeOneMillionDollars()
{
    await Task.Delay(2000);
    Console.WriteLine("Million Dollars Made!");
    return 1000000;
}

public static async Task WorldDomination()
{
    await Task.Delay(6000);
    Console.WriteLine("World Domination Achieved!");
}


Enter fullscreen mode Exit fullscreen mode

With output

Million Dollars Made!
Super Evil Plan Completed!
Mini Clone Created!
Evil Lair Built!
Henchman Hired!
World Domination Achieved!

alt text

Clearly this is a mess. Everything is happening at once. It's really fast - only dependent on the slowest method (6000ms). It's obvious that some calls are dependent on others. Now we need to synchronise them with each other.

Effectively Asynchronous

So, as an Evil Mastermind, which tasks would you run and in which order?

First, we need an evil lair. After that we can hire some henchman and create a mini clone of ourselves. Then we can come up with a Super Evil Plan, after which we can make One Million Dollars and achieve World Domination.

Changing the executing code we can achieve this by using the right mix of await and Task.WaitAll. Task.WaitAll fires off all the tasks asynchronously and finishes awaiting those tasks once all the tasks have completed - so the Task.WaitAll takes as long as the longest task it's awaiting.

Let's try this again.



// First we need an Evil Lair
await BuildAnEvilLair();

// Next, hire Henchman and create a Clone (asynchronously)
Task.WaitAll(HireSomeHenchman(), MakeMiniClone());

// Now, come up with the evil plan
await SuperEvilPlan();

// And finally, make One Million Dollars (and achieve World Domination)
Task.WaitAll(MakeOneMillionDollars(), WorldDomination());


Enter fullscreen mode Exit fullscreen mode

With output,

Evil Lair Built!
Henchman Hired!
Mini Clone Created!
Super Evil Plan Completed!
Million Dollars Made!
World Domination Achieved!

Taking a cool 18 000ms (18 seconds). 4 seconds less than the synchronous implementation.

So remember, next time you want to become an Evil Genius consider asynchronous execution and some time. If it's up to those darn super spies, every second counts!

Latest comments (31)

Collapse
 
mihirpa98294668 profile image
mihir patel

Very good web page, thank oneself for the exciting material for guaranteed I am going to be back.
kodlogs.net/1/task-delay-vs-thread...

Collapse
 
coderlegi0n profile image
CoderLegion

Task. Sleep is a synchronous thread that puts the thread to sleep so it can't be used for anything else. Task, on the other hand. Delay is an asynchronous thread that can be used to perform other tasks while it waits. Refer to this kodlogs.net/1/task-delay-vs-thread...

Collapse
 
vikasjk profile image
Vikas-jk

Good article, If someone stumbles upon this and want to read more about async-await in MVC, take a look
Asynchronous programming in C# and ASP.NET MVC ( With example )

Collapse
 
madebygps profile image
Gwyneth Peña-Siguenza

Fantastic explanation and I finally understand this topic! Haven't seen any recent posts of yours but I hope you continue to make some soon :)

Collapse
 
salem309 profile image
Ahmed Salem

Well written Henrick!!

Collapse
 
bellonedavide profile image
Davide Bellone

Cool!
A nice thing to know is that if the return type of a method is Task<int> you can return simply int and have .net work for you :)

code4it.dev/blog/asynchronous-prog...

Collapse
 
daverubin profile image
DaveRubin

Nice piece man!
Kudos

Collapse
 
luturol profile image
Rafael Ahrons

I loved the article!!

I've never understood async/await until now, and had to extract all those methods to another one and had it called from Main using .Wait(). I was like "Damn, that is good use and explanation" while laughing a lot

Collapse
 
jack profile image
Jack Williams

*One Meeeelion Dollars

Collapse
 
jamietwells profile image
jamietwells

There are so many misconceptions and bad habits in this article. Please update it with better code examples and clear up the misconceptions like the conflation between async and threads.