What are the differences between using Parallel.ForEach or Task.Run() to start a set of tasks asynchronously?
Version 1:
List<string> strings = new List<string> { "s1", "s2", "s3" };
Parallel.ForEach(strings, s =>
{
DoSomething(s);
});
Version 2:
List<string> strings = new List<string> { "s1", "s2", "s3" };
List<Task> Tasks = new List<Task>();
foreach (var s in strings)
{
Tasks.Add(Task.Run(() => DoSomething(s)));
}
await Task.WhenAll(Tasks);
In this case, the second method will asynchronously wait for the tasks to complete instead of blocking.
However, there is a disadvantage to use Task.Run
in a loop- With Parallel.ForEach
, there is a Partitioner
which gets created to avoid making more tasks than necessary. Task.Run
will always make a single task per item (since you're doing this), but the Parallel
class batches work so you create fewer tasks than total work items. This can provide significantly better overall performance, especially if the loop body has a small amount of work per item.
If this is the case, you can combine both options by writing:
await Task.Run(() => Parallel.ForEach(strings, s =>
{
DoSomething(s);
}));
Note that this can also be written in this shorter form:
await Task.Run(() => Parallel.ForEach(strings, DoSomething));