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?
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.
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.
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.
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?
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With