shay__
shay__

Reputation: 3990

Will every 'await' operator result in a state machine?

Please consider the following code:

public async Task<string> GetString()
{
    //Some code here...
    var data = await A();
    //Some more code...
    return data;
}
private async Task<string> A()
{
    //Some code here..
    var data = await B();
    //manipulating data...
    return data;
}
private async Task<string> B()
{
    //Some code here..
    var data = await C();
    //manipulating data...
    return data;
}
private async Task<string> C()
{
    //Some code here..
    var data = await FetchFromDB();
    //manipulating data...
    return data;
}
private async Task<string> FetchFromDB()
{
    return await SOME_HTTP_REQUEST;
}

This code demonstrate a most basic functionality - nested async methods. Will every method get translate into a state machine? Or is the compiler sophisticated enough to generate a more efficient structure? In some of my projects, there are ~20 methods between the UI/WebAPI and the I/O call - does that affect the trade-off between the async-await overhead (such as the state machine) and the non-blocking thread benefits? I mean, if, for example, the overhead of 4 state machines (4 nested async methods) equals to 50ms of blocking I/O (in terms of trade-off), will 20 state machine be equal to longer I/O's delay (250ms)?

Upvotes: 9

Views: 3477

Answers (3)

i3arnon
i3arnon

Reputation: 116568

await doesn't matter in this case. Each async method will generate a state machine (even if it has no awaits at all).

You can see that with this TryRoslyn example.

If you have cases where a state machine isn't needed, where the method doesn't really need to be async like this one for example:

private async Task<string> D()
{
    var data = await FetchFromDB();
    return data;
}

You can remove the async keyword and the state machine that comes with it:

private Task<string> D()
{
    return FetchFromDB();
}

But otherwise, you actually need the state machine and an async method can't operation without it.

You should note that the overhead is quite small and is usually negligible compared to the resources saved by using async-await. If you realize that's not the case (by testing) you should probably just make that operation synchronous.

Upvotes: 13

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149548

Will every method get translate into a state machine? Or is the compiler sophisticated enough to generate a more efficient structure?

No, the compiler will generate a state-machine for each of these calls. The compiler doesn't check the semantical call-chain of your methods. It will generate a state-machine on a method basis only.

You can see that clearly when looking at the compiled code:

Compiler generated code:

does that affect the trade-off between the async-await overhead (such as the state machine) and the non-blocking thread benefits?

You will have to test your code in order to be able to say that. Generally, async IO is good when you need through-put. If your async methods are going to be hit concurrently by multiple callers, you'll be able to see the benefits. If not, you might not see any effect of a performance gain. Again, benchmark your code.

Upvotes: 5

Servy
Servy

Reputation: 203835

Every method is going to have a state machine, yes.

Keep in mind that the "overhead" of the state machine is primarily the allocation of one object (that and a few gotos, which are going to be quite fast), so any type of "optimization" that you perform to remove it is the same as not creating an instance of a class once.

As to whether or not it's cost is greater or less than doing the work synchronously, that's something you're going to need to do performance benchmarks on given the specifics of your application and hardware to know for sure.

Upvotes: 8

Related Questions