DanJ
DanJ

Reputation: 21

How do I "WaitAll" on multiple spawned Task ConfigureAwait tasks?

I have a C# console app that spawns multiple task threads. I need to wait for all of them to finish before exiting the app otherwise it closes all the threads. How can I do a ".WaitAll()" on the ConfiguredTaskAwaiter (I'm assuming that's what I want to watch)

foreach (var entityType in entityTypes)
{
     // Create a task for each entity to thread the calls
     var task = Task.Run(() => TestTaskAsync(entityType)).ConfigureAwait(false); // Long running process
     var awaiter = task.GetAwaiter();
     Action showComplete = () => OnComplete($"PROCESSING FOR ENTITY ({entityType.Id}) HAS COMPLETED.");
     awaiter.OnCompleted(showComplete);
}

// Should not continue until all tasks have completed

Upvotes: 0

Views: 884

Answers (2)

Ordoshsen
Ordoshsen

Reputation: 770

Configure await does not change any property of the task itself, it just tells the compiler whether you care about your current context after you await the task. Therefore

var task = Task.Delay(1000);
// ...
await task.ConfigureAwait(false);

is identical to

var task = Task.Delay(1000).ConfigureAwait(false);
// ...
await task;

In your specific case, it makes no sense to configure await for tasks you're not actually planning to await. You should aggregate them and await them all together instead.

What you probably want to do is

var tasks = new List<Task>();

foreach (var type in types)
{
    var task = Task.Run(() =>
    {
        TestTaskAsync(entityType);
        OnComplete($"PROCESSING FOR ENTITY ({entityType.Id}) HAS COMPLETED.");
    });
    tasks.Add(task);
}

await Task.WhenAll(tasks).ConfigureAwait(false);

This tells the compiler that you do not care what context you will have after the await. Since you are not awaiting the individual tasks, it makes no sense to worry about context after awaiting those. You will only be awaiting a task that represents them all, that is the task returned by Task.WhenAll.

I also took the liberty of putting the continuation in the callback. If you do not want to do that for any reason, feel free to split it the way you have in your question, it will work the same way.

Upvotes: 4

nicecatch
nicecatch

Reputation: 1737

var taskList = new List<Task>();

foreach (var entityType in entityTypes)
{
    ....
    taskList.Add(task);
}

Task.WaitAll(taskList.ToArray())

but you should then async version called WhenAll :

await Task.WhenAll(taskList)

Upvotes: 0

Related Questions