How to get results from List<T>.AsParallel() in C#

93 Views Asked by At

I have an asynchronous

async static public Task<int> Test(int x, int y)
{
   await Task.Delay(1000);
   return x;
}

And I try to run it in parallele on a list. I did like that:

var x = new[] { 0, 1 };
var y = new[] { 2, 3 };
var zipped = x.Zip(y, (x, y) => new { x, y }).ToList();
zipped.AsParallel().ForAll(async pair => { await Test(pair.x, pair.y); });

But I don't manage to retrieve the list it should return [0,1] cause the AsParallel returns void

Any idea ? also, if there is better solution to speed up in true parralel programming, I take

1

There are 1 best solutions below

5
Guru Stron On

AsParallel returns void

If AsParallel would have returned void then you would not be able to call ForAll on it's result. It is ForAll which has void return type.

If you want to get the result - use Select:

List<Task<int>> parallelQuery = zipped.AsParallel()
   .Select(async pair => await Test(pair.x, pair.y))
   // which is almost the same as .Select(pair => Test(pair.x, pair.y))
   .ToList();

BUT PLINQ is not async/Task-aware (as you can somewhat see by the return type) so if your Test is purely IO-bound it does not make much sense here since it will just start all the tasks without actually limiting number of tasks scheduled in parallel (i.e. only task creation is parallelized). Hence it would be similar to just using ordinary LINQ:

IEnumerable<Task<int>> parallelQuery = zipped
    .Select(async pair => await Test(pair.x, pair.y));
int[] result = await Task.WhenAll(parallelQuery);

If you want to limit concurrently "scheduled"/running tasks you can use SemaphoreSlim or Parallel.ForEachAsync. For example:

var results = new int[zipped.Count];

Parallel.ForEachAsync(
    zipped.Select((t, i) => (t, i)), // zip with index
    async (tuple, ct) =>
    {
        var t = tuple.t;
        results[tuple.i] = await Test(t.x, t.y); // Pass CancellationToken - ct to test
    });

See also: