c#: async awaits - under the hood
So the concept of async awaits
is just the standard asynchronous vs synchronous topic. I've written about that before for freeCodeCamp.
But, the C# under the hood state machine is new to me.
Some concepts I learnt
When is it relevant to use
async awaits
?You don't need to immediately
await
the taskasync await
generates a lot of code under the hoodasync
allows your system to scale
When is it relevant to use async awaits
?
There are two relevant use cases for async awaits
I/O-bound: when you are waiting for something, like reading from a database, writing to a database
CPU-bound: when you don't want to freeze your UI (at work, this use case is not relevant for us)
You don't need to immediately await
the task
You can separate
kicking off of the task, and
using the result of the task (which takes some time before it's ready to be used)
At Empower we often need the result straight away, which is why we almost always use var result = await CreamButterAndSugarAsync();
Here's how I think you would separate the two, based on some YouTube clips
But I get the feeling this is wrong
I think you actually need to do something like
CreamButterAndSugarAsync().Start / .Run
or something like that.
private async Task<Batter> CreamButterAndSugarAsync()
{
// some task that will take 8 minutes to finish
// return Batter;
}
public async Task MakeBananaCake()
{
var creamButterAndSugarTask = CreamButterAndSugarAsync();
// Go do all the other things now, whilst the butter and sugar are creaming
// This will take ages, and you don't need the result yet
// e.g. measure out flour, separate the eggs
// once you are ready to use the result of the task, then you call `await`
var batter = await creamButterAndSugarTask;
// add eggs to `batter`
}
async await
generates a lot of code under the hood
So use it only if you need to.
Every extra argument you pass into your async method creates another property to manage the state of.
So consider what you really need.
This is a good ILSpy browser based tool
I put in the below code to see the async state machine
using System;
using System.Threading.Tasks;
public class C {
public async Task M() {
var result = await MakeCake();
Console.WriteLine(result);
}
private async Task<string> MakeCake()
{
await Task.Delay(1000);
return "Cake finished!";
}
}
It comes back with a LOT of code.
async
allows your system to scale
So. You have some code that does this inside a public class MakeCake
var cakeBatter = await MakeCakeBatterAsync();
var pourIntoPan = await PourIntoPanAsync(cakeBatter);
var cookedCake = await PutInOvenAsync(cakeBatter, 200C, 20mins);
var icedCake = await CoolDownThenIceAsync(cookedCake, 20mins);
Here's the thing. These are all async functions, because you are getting them to do things that take time.
BUT, they are run one after the other.
You are waiting for the output of one, so that you can use it as the input to the next.
So.. it looks kinda "synchronous" to me.
Why bother with the async
?
To optimise "resource allocation" (that may not be the right term). But basically, to make good use of your resources.
If you made everything synchronous, for your particular
MakeCake
class, there would be no change when you ran it once, for one user.- The server holds on to the
MakeCake
class, and until everything is finished, it just sitsMakeCake
and holds its hand the entire time
- The server holds on to the
BUT, if you have multiple requests to
MakeCake
, all of a sudden, your resources are going to be tied up, and you won't be able to fulfil many cake orders when you are running them all synchronously.If
MakeCake
is made up ofasync await
methodsEach time an async method is called, that "instance" of
MakeCake
can be "released" and used to go do something else, as the state machine holds the state ofMakeCake
Until the async method is finished, the server knows there's nothing else it can do.
Whilst it waits for the method to finish, the server can go away and use that resource to do something else, like make another cake (instead of sitting there, holding the hand of the synchronous
MakeCake
)
With async methods, you can exponentially increase the number of cakes you can make per second
So.. async await
will not speed up the time it takes to make ONE cake.
But, it will mean that you can make 10,000 cakes at once, instead of only 5 cakes at once.