Reputation: 6694
public class Input
{
public bool ParameterOne { get; set; }
public string ParameterTwo { get; set; }
}
I have a List<Input>
that I want to process in parallel, keeping the input associated with the output. I loop through this list to build Task
s.
var results = new List<(Input, Output)>();
foreach (var input in inputs)
{
Output output = await Process(input);
results.Add((input, output));
}
But this is not operating in parallel. I would like it to.
var inputsAndTasks = new List<(Input Input, Task<Output> OutputTask)>();
foreach (var input in inputs)
{
Task<Output> output = Process(input);
inputsAndTasks.Add((input, output));
}
Output[] results = await Task.WhenAll(inputsAndTasks.Select(i => i.OutputTask));
// results are no longer associated with their inputs!
How can I run this in parallel but retain the input association with the output? I don't want to make the input an object on the output.
Upvotes: 2
Views: 396
Reputation: 535
There is an alternative approach that avoids using tasks altogether by taking advantage of "AsParallel"
IList<Input> inputs = new List<Input>();
// populate inputs here
IDictionary<Input, Output> associations = new Dictionary<Input, Output>();
associations.AddRange(inputs.AsParallel()
.Select(async i =>
{ Output o = await Process(i);
return new KeyValuePair<Input, Output>(i, o);
}));
Upvotes: 3
Reputation: 32266
You can just await the WhenAll
then do a loop to match up the input and output
var inputsAndTasks = new List<(Input Input, Task<Output> OutputTask)>();
foreach (var input in inputs)
{
Task<Output> output = Process(input);
inputsAndTasks.Add((input, output));
}
await Task.WhenAll(inputsAndTasks.Select(i => i.OutputTask));
var results = new List<(Input, Output)>();
foreach (var x in inputsAndTasks)
{
Output output = await x.OutputTask;
results.Add((x.Input, output));
}
Since you already know all the individual output tasks are complete doing the await
in that second loop will return the result immediately.
Upvotes: 0