Reputation: 720
I have trouble understanding control flow during await when I have two tasks and I await one. The Control Flow in Async Programs (C# and Visual Basic) uses only one await so it didn't help.
I have following code:
public async Task Loop(string name, int count)
{
for (int i = 0; i < count; i++)
{
Console.WriteLine("{0}: {1} Before", name, i);
await Task.Delay(10);
Console.WriteLine("{0}: {1} After", name, i);
}
Console.WriteLine("{0} COMPLETE", name);
}
[TestMethod]
public async Task TwoLoopsWithSeparateAwait()
{
var loopOne = Loop("ONE", 3);
Console.WriteLine("After ONE Creation");
var loopTwo = Loop("TWO", 3);
Console.WriteLine("After TWO Creation, before ONE await");
await loopOne;
Console.WriteLine("After ONE await");
await loopTwo;
Console.WriteLine("After TWO await");
}
with following result:
According to the await (C# Reference):
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
I understand what happens until await loopOne, but I thought that only loopOne would be executed (probably synchronously), it looks like await behaves more like a yield that keeps list of possible tasks that may continue (I suppose that qualifies for "When the task completes, it invokes its continuation").
What is the logic behind control flow during await for multiple tasks?
Upvotes: 3
Views: 1296
Reputation: 116636
An async
method is executed synchronously until it reaches an await
. It then creates a task that represents the async
operation you're awaiting together with the rest of the code as a continuation to be executed when the operation completes. That means that in an async
method when the first await
is reached the control is actually returned to the caller with a hot task. When an await
is reached inside that continuation it again registers a continuation and so forth.
So in your case, the execution order should be:
The continuations in the middle could easily be in a different order depending on how long the asynchronous operations actually took.
You could imagine 3 different flows here. The first one executes the synchronous parts of both Loop
calls, start 2 concurrent flows of async
operations and continuations and then registers a continuation to the first call that will register a continuation to the second.
Upvotes: 6