By Daniel Minnaar


2014-07-29 06:34:28 8 Comments

I need to run multiple async tasks in a console application, and wait for them all to complete before further processing.

There's many articles out there, but I seem to get more confused the more I read. I've read and understand the basic principles of the Task library, but I'm clearly missing a link somewhere.

I understand that it's possible to chain tasks so that they start after another completes (which is pretty much the scenario for all the articles I've read), but I want all my Tasks running at the same time, and I want to know once they're all completed.

What's the simplest implementation for a scenario like this?

8 comments

@NtFreX 2017-06-16 21:21:26

You can use WhenAll which will return an awaitable Task or WaitAll which has no return type and will block further code execution simular to Thread.Sleep until all tasks are completed, canceled or faulted.

enter image description here

Example

var tasks = new Task[] {
    TaskOperationOne(),
    TaskOperationTwo()
};

Task.WaitAll(tasks);
// or
await Task.WhenAll(tasks);

If you want to run the tasks in a praticular order you can get inspiration form this anwser.

@dee zg 2019-03-14 16:00:50

sorry for coming to the party late but, why do you have await for each operation and at the same time use WaitAll or WhenAll. Shouldn't tasks in Task[] initialization be without await?

@NtFreX 2019-03-14 16:04:51

@dee zg You are right. The await above defeats the purpose. I ll change my answer and remove them.

@dee zg 2019-03-14 16:06:02

yes, that's it. thanks for clarification! (upvote for nice answer)

@sayah imad 2019-02-14 13:58:07

I prepared a piece of code to show you how to use the task for some of these scenarios.

    // method to run tasks in a parallel 
    public async Task RunMultipleTaskParallel(Task[] tasks) {

        await Task.WhenAll(tasks);
    }
    // methode to run task one by one 
    public async Task RunMultipleTaskOneByOne(Task[] tasks)
    {
        for (int i = 0; i < tasks.Length - 1; i++)
            await tasks[i];
    }
    // method to run i task in parallel 
    public async Task RunMultipleTaskParallel(Task[] tasks, int i)
    {
        var countTask = tasks.Length;
        var remainTasks = 0;
        do
        {
            int toTake = (countTask < i) ? countTask : i;
            var limitedTasks = tasks.Skip(remainTasks)
                                    .Take(toTake);
            remainTasks += toTake;
            await RunMultipleTaskParallel(limitedTasks.ToArray());
        } while (remainTasks < countTask);
    }

@PreguntonCojoneroCabrón 2019-11-14 19:59:59

how get the results of Tasks? For example, for merge "rows" (from N tasks in parallel) in a datatable and bind it to gridview asp.net ?

@Yehor Hromadskyi 2018-10-17 11:53:04

Yet another answer...but I usually find myself in a case, when I need to load data simultaneously and put it into variables, like:

var cats = new List<Cat>();
var dog = new Dog();

var loadDataTasks = new Task[]
{
    Task.Run(async () => cats = await LoadCatsAsync()),
    Task.Run(async () => dog = await LoadDogAsync())
};

try
{
    await Task.WhenAll(loadDataTasks);
}
catch (Exception ex)
{
    // handle exception
}

@Stephen Kennedy 2019-10-10 14:45:44

If LoadCatsAsync() and LoadDogAsync() are just database calls they are IO-bound. Task.Run() is for CPU-bound work; it adds additional unnecessary overhead if all you are doing is waiting for a response from the database server. Yuval's accepted answer is the right way for IO-bound work.

@Yehor Hromadskyi 2019-10-11 15:51:58

@StephenKennedy could you please clarify what kind of overhead and how much it can impact performance? Thanks!

@Stephen Kennedy 2019-10-11 17:07:17

That would be quite hard to summarise in the comments box :) Instead I recommend reading Stephen Cleary's articles - he's an expert on this stuff. Start here: blog.stephencleary.com/2013/10/…

@Yuval Itzchakov 2014-07-29 07:29:58

Both answers didn't mention the awaitable Task.WhenAll:

var task1 = DoWorkAsync();
var task2 = DoMoreWorkAsync();

await Task.WhenAll(task1, task2);

The main difference between Task.WaitAll and Task.WhenAll is that the former will block (similar to using Wait on a single task) while the latter will not and can be awaited, yielding control back to the caller until all tasks finish.

More so, exception handling differs:

Task.WaitAll:

At least one of the Task instances was canceled -or- an exception was thrown during the execution of at least one of the Task instances. If a task was canceled, the AggregateException contains an OperationCanceledException in its InnerExceptions collection.

Task.WhenAll:

If any of the supplied tasks completes in a faulted state, the returned task will also complete in a Faulted state, where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks.

If none of the supplied tasks faulted but at least one of them was canceled, the returned task will end in the Canceled state.

If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the RanToCompletion state. If the supplied array/enumerable contains no tasks, the returned task will immediately transition to a RanToCompletion state before it's returned to the caller.

@Zapnologica 2016-08-22 08:04:18

When I try this my tasks run sequentially? Does one have to start each task individually before await Task.WhenAll(task1, task2); ?

@Yuval Itzchakov 2016-08-22 08:11:23

@Zapnologica Task.WhenAll doesn't start the tasks for you. You have to provide them "hot", meaning already started.

@Zapnologica 2016-08-22 08:24:11

Ok. That makes sense. So what will your example do? Because you have not started them?

@Yuval Itzchakov 2016-08-22 08:53:55

@Zapnologica In my example, both methods are the one to kick off the tasks. Task.WhenAll asynchronously waits for both of them to complete, but their execution happens concurrently.

@batmaci 2016-10-06 12:07:47

is it the same to call Await Tasks.Task.Run(()=>dowork) for each function sequentially?

@Yuval Itzchakov 2016-10-06 12:09:03

@batmaci No, await on each Task will await each task one at a time. using Task.WhenAll will concurrently wait for the completion of all tasks.

@dee 2017-03-25 17:41:03

@YuvalItzchakov thank you very much! It is so simple but it helped me a lot today! Is worth at least +1000 :)

@Pierre 2018-04-06 07:15:17

if you are not going to use await Task.WhenAll(...) then you can just StartNew on all the tasks and let it be

@Yuval Itzchakov 2018-04-06 09:16:51

@Pierre I'm not following. What does StartNew and spinning new tasks have to do with asynchronously waiting on them all?

@Pierre 2018-04-06 10:19:09

Nothing at all :)

@Ryan 2018-06-14 21:46:58

If there is an exception thrown inside of DoWorkAsync() or DoMoreWorkAsync() before the await calls are reached, won't the exception be lost? docs.microsoft.com/en-us/dotnet/visual-basic/language-refere‌​nce/…

@Yuval Itzchakov 2018-06-15 07:54:19

@Ryan AFAIR Exceptions that happen before the first await point are thrown synchronously.

@DalSoft 2017-05-23 11:30:08

This is how I do it with an array Func<>:

var tasks = new Func<Task>[]
{
   () => myAsyncWork1(),
   () => myAsyncWork2(),
   () => myAsyncWork3()
};

await Task.WhenAll(tasks.Select(task => task()).ToArray()); //Async    
Task.WaitAll(tasks.Select(task => task()).ToArray()); //Or use WaitAll for Sync

@Talha Talip Açıkgöz 2017-12-08 14:47:05

Why don't you just keep it as Task Array?

@DalSoft 2018-06-19 16:55:04

If your not careful @talha-talip-açıkgöz your execute the Tasks when you didn't expect them to execute. Doing it as a Func delegate makes your intent clear.

@Virus 2014-07-29 06:45:42

You could create many tasks like:

List<Task> TaskList = new List<Task>();
foreach(...)
{
   var LastTask = new Task(SomeFunction);
   LastTask.Start();
   TaskList.Add(LastTask);
}

Task.WaitAll(TaskList.ToArray());

@Ravi 2014-12-16 19:58:34

I would recommend WhenAll

@Matt W 2015-09-01 06:36:17

Is it possible to start multiple new threads, at the same time, using the await keyword rather than .Start() ?

@Virus 2015-09-01 08:40:47

@MattW No, when you use await, it would wait for it to complete. In this case you would not be able to create a multi-threaded environment. This is the reason that all the tasks are waited at the end of the loop.

@JRoughan 2016-10-11 01:56:59

Downvote for future readers since it isn't made clear that this is a blocking call.

@EL MOJO 2017-09-06 16:30:20

See the accepted answer for reasons why not to do this.

@me22 2015-09-13 20:52:41

The best option I've seen is the following extension method:

public static Task ForEachAsync<T>(this IEnumerable<T> sequence, Func<T, Task> action) {
    return Task.WhenAll(sequence.Select(action));
}

Call it like this:

await sequence.ForEachAsync(item => item.SomethingAsync(blah));

Or with an async lambda:

await sequence.ForEachAsync(async item => {
    var more = await GetMoreAsync(item);
    await more.FrobbleAsync();
});

@Andreas Niedermair 2014-07-29 06:36:01

Do you want to chain the Tasks, or can they be invoked in a parallel manner?

For chaining
Just do something like

Task.Run(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
Task.Factory.StartNew(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);

and don't forget to check the previous Task instance in each ContinueWith as it might be faulted.

For the parallel manner
The most simple method I came across: Parallel.Invoke Otherwise there's Task.WaitAll or you can even use WaitHandles for doing a countdown to zero actions left (wait, there's a new class: CountdownEvent), or ...

@Daniel Minnaar 2014-07-29 06:56:11

Appreciate the answer, but your suggestions could have been explained a little more.

@Andreas Niedermair 2014-07-29 07:08:20

@drminnaar which other explanation beside the links to msdn with examples do you need? you didn't even click on the links, did you?

@Daniel Minnaar 2014-07-29 08:24:11

I clicked on the links, and I read the content. I was going for the Invoke, but there were a lot of If's and But's about whether it runs asynchronously or not. You were editing your answer continuously. The WaitAll link you posted was perfect, but I went for the answer that demonstrated the same functionality in a quicker and easier to read way. Don't take offense, your answer still provides good alternatives to other approaches.

@Andreas Niedermair 2014-07-29 09:06:10

@drminnaar no offense taken here, i am just curious :)

Related Questions

Sponsored Content

11 Answered Questions

[SOLVED] How to safely call an async method in C# without await

26 Answered Questions

[SOLVED] Why not inherit from List<T>?

11 Answered Questions

[SOLVED] Call async/await functions in parallel

14 Answered Questions

[SOLVED] Asynchronously wait for Task<T> to complete with timeout

7 Answered Questions

[SOLVED] Run two async tasks in parallel and collect results in .NET 4.5

24 Answered Questions

[SOLVED] How would I run an async Task<T> method synchronously?

4 Answered Questions

5 Answered Questions

[SOLVED] Using async/await for multiple tasks

3 Answered Questions

Sponsored Content