2
private async void btnTest_Click(object sender, EventArgs e)
        {
            List<Task> lstTasks = new List<Task>();
            foreach (int val in lstItems)
            {
                lstTasks.Add(MyAsyncMtd(val));
            }
            await Task.WhenAll(lstTasks);
            ...
        }

        private async Task MyAsyncMtd(int val)
        {
            ...
            await Task.Delay(1000);
            ...
        }

Question: On button click, at the 1st iteration of the for loop, when the await keyword in the MyAsyncMtd is encountered, then I know that the control goes to the caller. The caller in this case is the button click method. Does this mean that the next iteration gets processed while waiting (Task.Delay) on the 1st iteration's Task.Delay (in other words - does await return Task to the caller?)? or what happens exactly?

variable
  • 8,262
  • 9
  • 95
  • 215
  • 1
    "_Does this mean that the next iteration gets processed while waiting (Task.Delay)_" -> Yes. – Johnathan Barclay Sep 02 '21 at 09:31
  • Does this answer your question? [How do yield and await implement flow of control in .NET?](https://stackoverflow.com/questions/42287737/how-do-yield-and-await-implement-flow-of-control-in-net) – Charlieface Sep 02 '21 at 09:31
  • It's technically the first await that may create the continuation. However when you call an async method without awaiting it, it starts starts the task hot. So you are creating lots of tasks all at once then awaiting them. No iterations are harmed in the making of this storey – TheGeneral Sep 02 '21 at 09:36
  • What happens if I do `lstTasks.Add(await MyAsyncMtd(val));` ? – variable Sep 02 '21 at 10:07
  • The same thing exvept a boatload less efficiently. You could play this game all day, (the whole what of this and that and something else) it doesn't solve your general research problem though – TheGeneral Sep 02 '21 at 10:10
  • It's not clear what problem you're trying to solve. Is it about what is executed in `MyAsyncMtd()` right after you add the Task to the List? If it's about *observation* of the results, you just need to *observe* them. -- Do you have sync code that is executed before the await in your async method? Some other call that returns a completed Task right away? Does it cause some sort of reentrancy? Exceptions? Other? – Jimi Sep 02 '21 at 10:16
  • When the for loop is executing, then how does the MyAsyncMtd add a task to the list without returning a task (assuming at await it will move to the next iteration)? – variable Sep 02 '21 at 14:03

1 Answers1

3

The next iteration occurs without any waiting - because you haven't awaited the task yet. So you'll very quickly go through the foreach loop and reach the Task.WhenAll. That will complete when all the tasks have completed, i.e. 1 second after the final Task.Delay(1000) call was executed.

The await operator doesn't always trigger the method returning immediately - it only does so when the operand isn't already completed. For example, consider this code:

public async Task Method1()
{
    Console.WriteLine("1");
    Task task = Method2();
    Console.WriteLine("2");
    await task
    Console.WriteLine("3");
}

public async Task Method2()
{
    Console.WriteLine("a");
    await Task.FromResult(10);
    Console.WriteLine("b");
    await Task.Delay(1000);
    Console.WriteLine("c");
}

I'd expect the output to be:

1 // Before anything else happens at all in Method1
a // Call to Method2, before the first await
b // The first await didn't need to return, because the FromResult task was complete
2 // Control returned to Method2 because the Delay task was incomplete
c // Awaiting the result of Method1 means the rest of Method1 executes
3 // All done now
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Will writing like the following make any difference to the way my code runs: `lstTasks.Add(await MyAsyncMtd(val));` – variable Sep 02 '21 at 09:46
  • 3
    @variable That wouldn't compile because `await MyAsyncMtd(val);` doesn't return anything given your example code. Even if it did return something, whatever is returned isn't a `Task` once it is unwrapped as part of `await`, so you wouldn't be able to add it to `lstTasks` anyway (unless your async method is literally `private async Task MyAsyncMtd(int val);`). – ProgrammingLlama Sep 02 '21 at 10:20
  • I would like to know that- since await doesn't return a task, then how come the iteration proceeds to add task to the list? – variable Sep 02 '21 at 14:09
  • 1
    @variable: It's unclear to me what you mean, because "since await doesn't return a task" is somewhat imprecise. The result type of the `await` operator is either nothing or the unwrapped type being awaited; the `await` operator *causes the async method to return a task immediately* if the awaitable expression has not already completed. – Jon Skeet Sep 02 '21 at 14:55
  • Suppose the iteration was very large, such that the iterations are not complete after 1 second, then would the 1st tasks call back execute and block the subsequent iterations? – variable Sep 02 '21 at 18:02
  • 1
    @variable I would suggest you build on Jon's example to test your various scenarios. – ProgrammingLlama Sep 03 '21 at 02:40