19

Hopefully a fairly simple one here. I have a collection of objects, each of which has an async method that I want to call and collect values from. I'd like them to run in parallel. What I'd like to achieve can be summed up in one broken line of code:

IEnumerable<TestResult> results = await Task.WhenAll(myCollection.Select(v => v.TestAsync()));

I've tried various ways of writing this without success. Any thoughts?

wwarby
  • 1,873
  • 1
  • 21
  • 37

2 Answers2

18

If the tasks you're awaiting have a result of the same type Task.WhenAll returns an array of them. For example for this class:

public class Test
{
    public async Task<TestResult> TestAsync()
    {
        await Task.Delay(1000); // Imagine an I/O operation.
        return new TestResult();
    }
}

We get these results:

var myCollection = new List<Test>();
myCollection.Add(new Test());

IEnumerable<TestResult> results = await Task.WhenAll(myCollection.Select(v => v.TestAsync()));
i3arnon
  • 113,022
  • 33
  • 324
  • 344
  • 4
    @I3arnon: this is the same code, which OP had written. It's better to clarify, what doesn't work for him. – Dennis Nov 10 '14 at 08:59
  • I've explained what should work and why. I'm waiting for the OP to clarify what doesn't work for him. – i3arnon Nov 10 '14 at 09:04
  • 4
    I'm an idiot - My TestAsync method was returning a Task rather than a Task - as soon as I changed that, it worked. Thanks for pointing me in the right direction - I couldn't see what was wrong even though it was riht in front of me! – wwarby Nov 10 '14 at 12:16
  • Could you supply an example where `TestAsync` accepts parameters, and is a `static` method ? – Kraang Prime Jul 30 '16 at 22:56
  • What worked for me was replacing `Task.WaitAll` with `await Task.WhenAll` in [this answer](https://stackoverflow.com/a/25319520/1684720) – gattsbr Oct 21 '20 at 03:15
0

Do it like this:

public async Task RunMultipleTasksInParallelAsync()
{
    var tasks = new List<Task<MyResultType>>(); //<---- Add the return type here

    foreach (var item in items)
    {
        var task = DoSomethingAsync();
        tasks.Add(task);
    }

    var myResults = await Task.WhenAll(tasks);
}

public async Task<MyResultType> DoSomethingAsync()
{
    return new MyResultType();
}

Recogize that you have to add the return type into the task list, otherwhise Task.WhenAll will have the return type void.