Adding tasks to a List<Task> executes them making Task.WhenAll() redundant

Viewed 487

I have a bunch of async web queries that I need to run at application startup. Why in this example both tasks execute even if I comment out this line?

//await Task.WhenAll(tasks);

It seems that there is no difference whether I use Task.WhenAll() or not. How come?

static void Main(string[] args)
{
    Execute();
    Console.ReadKey();
}

private static async void Execute()
{
    Func<Task> Task1 = (async () =>
    {
        await Task.Delay(1000);
        Console.WriteLine("Task 1 completed.");
    });

    var tasks = new List<Task> { Task1(), Task2() };

    await Task.WhenAll(tasks);
}

private static async Task Task2()
{
    await Task.Delay(1000);
    Console.WriteLine("Task 2 completed.");
}
1 Answers

All WhenAll does is construct a new Task that will be completed when all of the tasks provided to it have completed (and propagating errors/cancellation/results as appropriate). It doesn't start anything, or do anything. Any changes to the behavior of your program have to do with what you do with the Task it returns, that's all.

The methods start executing when you call them, which is done here:

var tasks = new List<Task> { Task1(), Task2() };

Note that if your method returned a Task, then without the await Task.WhenAll that Task would be completed as soon as you finished starting the tasks, rather than when they finished running, and the returned task wouldn't be faulted if either of the tasks error out or are cancelled. With the WhenAll, if your Execute method returned a task, it wouldn't finish until both of those tasks had finished, and would propagate their errors.

But since you used an async void method, which you need to be very careful about using (it's usually wrong to write such a method, as is the case here) there's no way for the caller of the method to even observe the difference between you using WhenAll or not.

Related