Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

await/async and going outside the box

I have a question regarding await/async and using async methods in slightly different scenarios than expected, for example not directly awaiting them. For example, Lets say I have two routines I need to complete in parallel where both are async methods (they have awaits inside). I am using await TAsk.WhenAll(...) which in turn expects some sort of list of tasks to wait for. What I did is something like this:

            await Task.WhenAll(new Task[]
            { 
                Task.Run(async () => await internalLoadAllEmailTargets()),
                Task.Run(async () => await internalEnumerateInvoices())
            });

This seems overly elaborate to me, in the sense that I am creating async tasks whose sole purpose is to invoke another task. Can't I just use tasks which are returned from the async method state engine? Yet, I am failing to do that since compiler treats every direct mention of async method as an invocation point:

            // this doesn't seem to work ok
            await Task.WhenAll(new Task[]
            { 
                internalLoadAllEmailTargets(),
                internalEnumerateInvoices()
            }); 

If its like this, it seems to synchronously calls one after another, and if I place await in front of methods, it is no longer a Task. Is there some rule book on how async methods should be handled outside plain await?

like image 932
mmix Avatar asked Jul 27 '15 17:07

mmix


People also ask

Does await pause the code?

The await expression causes async function execution to pause until a promise is settled (that is, fulfilled or rejected), and to resume execution of the async function after fulfillment. When resumed, the value of the await expression is that of the fulfilled promise.

Is await async blocking?

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.

Does await block the thread?

The await operator doesn't block the thread that evaluates the async method. When the await operator suspends the enclosing async method, the control returns to the caller of the method.

Does await throw exception?

If we use the “await” keyword, the exception will be thrown: This solves the problem for a single simple task, but what if we have multiple tasks running within a method?


Video Answer


2 Answers

Every async method starts executing synchronously, but when it hits its first await, it may behave asynchronously. So this line:

await Task.WhenAll(internalLoadAllEmailTargetsAsync(), internalEnumerateInvoicesAsync());

should work just fine. It is roughly equivalent to this:

var _1 = internalLoadAllEmailTargetsAsync();
var _2 = internalEnumerateInvoicesAsync();
await Task.WhenAll(_1, _2);

If your methods are truly asynchronous, then this should be fine.

Now, if your methods are actually doing some synchronous work - say, heavy CPU-bound code - then you may want to use Task.Run to invoke them (if your calling code is on a UI thread).

like image 103
Stephen Cleary Avatar answered Sep 23 '22 05:09

Stephen Cleary


You have some code, which creates Task object, and it will be invoked as usual, i.e synchronously. Control will be returned to the invoking code only after Task creation and in case of async it will be after the first await. So, if it's a problem, that some part of your method will be invoked in blocking manner, you could use Task.Yield at the beginning, just be careful with SynchronizationContext and thread switches.

But in most cases there is nothing wrong with that scenario, because code, which creates Task, is small and fast, while actual timing is caused by some sort of IO operation.

like image 32
Uładzisłaŭ Avatar answered Sep 21 '22 05:09

Uładzisłaŭ