Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does C# await keyword cause the function call to block?

I am trying to grok how async and await works in C#.

Consider the two snippets below:

var appIdTask = GetAppIdAsync();
var clientSecretTask = GetClientSecretAsync();
var appId = await appIdTask;
var clientSecret = await clientSecretTask;
Execute(appId, clientSecret);

and

var appId = await GetAppIdAsync();
var clientSecret = await GetClientSecretAsync();
Execute(appId, clientSecret);

These two snippets have different implications. Correct?

First one will make the Get calls in parallel whereas the second one will make the calls in serial?

From my understanding, the await keyword on the first call blocks the execution on the second call.

like image 411
ashwnacharya Avatar asked May 08 '20 07:05

ashwnacharya


3 Answers

It doesn't "block" in the traditional sense of "halting the current thread in the current state until some signal is received" (one of the main objectives of async is to increase throughout by allowing more effective use of pool threads, by having them not all sat idly waiting for IO), but yes: if the method reports that it is incomplete, the execution will be suspended by await, and resumed (quite likely on a different shared thread) when the async result is available.

So yes, semantically it has the effect of not running the two things concurrently (note this only applies if the first call is truly asynchronous).

Note that many APIs do not expect multiple concurrent async operations, and will have undefined behaviour in the first example.

like image 160
Marc Gravell Avatar answered Nov 14 '22 19:11

Marc Gravell


One important rule about async/awaits is that a method with the async modifier will run synchronously until it gets to the first incomplete Task.

Async is not about parallelism but asynchronism. It's not based on the fact that the method is async but on the state of the Task being returned.

I invite you to take a look at this post, and its code example.

like image 37
hardkoded Avatar answered Nov 14 '22 19:11

hardkoded


So in the first snippet:


var appIdTask = GetAppIdAsync(); // here we are starting the execution of GetAppId on another thread, no "blocking" the main one
var clientSecretTask = GetClientSecretAsync(); // instantly after starting previous method, run GetClientSecrent on yet another thread
// at this point there are 2 parallel executions on different threads happening
var appId = await appIdTask; // wait until GetAppId has finished and assign the result to appId variable
var clientSecret = await clientSecretTask; // wait until GetClientSecret has finished and assign the result to clientSecret variable
Execute(appId, clientSecret);

And the second snippet:

var appId = await GetAppIdAsync(); // start executing GetAppId on different thread (not blocking the main one), and return once it has been completed and assign the result to appId variable
// at this point GetAppIdAsync is completed
var clientSecret = await GetClientSecretAsync(); // start executing GetClientSecret on different thread (not blocking the main one), and return once it has been completed and assign the result to appId clientSecret 
// at this point GetClientSecretAsync is completed
Execute(appId, clientSecret);

If you need to run multiple calls in parallel, I recomend using Task.WhenAll

like image 1
Jakub Kozera Avatar answered Nov 14 '22 20:11

Jakub Kozera