Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)?

like image 781
shay__ Avatar asked Mar 09 '15 14:03

shay__


People also ask

What does the await operator do?

The await operator suspends evaluation of the enclosing async method until the asynchronous operation represented by its operand completes. When the asynchronous operation completes, the await operator returns the result of the operation, if any.

Does await actually wait C#?

await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.

Does await block?

await only blocks the code execution within the async function. It only makes sure that the next line is executed when the promise resolves. So, if an asynchronous activity has already started, await will not have an effect on it.

What happens if you don't await an async method C#?

If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown. As a best practice, you should always await the call. By default, this message is a warning.


3 Answers

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.

like image 53
i3arnon Avatar answered Oct 17 '22 18:10

i3arnon


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.

like image 29
Servy Avatar answered Oct 17 '22 16:10

Servy


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.

like image 5
Yuval Itzchakov Avatar answered Oct 17 '22 18:10

Yuval Itzchakov