Simon Trewhella
Simon Trewhella

Reputation: 2484

Execute list of async tasks

I have a list of async functions I want to execute in order. When I run the following code I get the output:

Task 1 before
Task 2 before
Finished tasks

Why are my async functions not being awaited correctly?

    [Test]
    public async Task AsyncTaskList()
    {
        var data = "I'm data";
        var tasks = new List<Func<object, Task>>() {Task1, Task2};

        tasks.ForEach(async task =>
        {
            await task(data);
        });

        Debug.WriteLine("Finished tasks");
    }

    private static async Task Task1(object data)
    {
        Debug.WriteLine("Task 1 before");
        await Task.Delay(1000);
        Debug.WriteLine("Task 1 after");
    }

    private static async Task Task2(object data)
    {
        Debug.WriteLine("Task 2 before");
        await Task.Delay(1000);
        Debug.WriteLine("Task 2 after");
    }

Upvotes: 0

Views: 1438

Answers (1)

Kirill Shlenskiy
Kirill Shlenskiy

Reputation: 9587

Because the await inside your ForEach delegate actually completes after the method exits. Change it to an actual foreach loop and awaiting will work as expected.

ForEach has no specific handling for Func<Task> (few delegate-accepting methods in the Base Class Library do, and you should note that they will almost invariably return a Task themselves). ForEach will only run the synchronous portion of your lambda - and that is the portion preceding the first await of a Task which does not complete synchronously (which is Task.Delay in your case). This is why you're seeing the "before" messages popping up at the expected time. As soon as your delegate hits await Task.Delay, the the rest of your lambda is scheduled to run sometime in the future and ForEach moves on to the next item in the list. The scheduled task continuations will then run unobserved and complete later.

Upvotes: 4

Related Questions