Is there a way to guarantee order when using Parallel.ForEach()
? The collection I am looping over needs to maintain it's order but I was looking for some performance improvement.

- 34,835
- 7
- 69
- 104

- 7,514
- 26
- 77
- 144
-
1What do you mean by "guarantee order"? For example, if you have 5 threads and item 3 finishes before item 4 then thread 3 will start with item 6, and as this goes on you are not certain about the order. Is that the problem you are trying to solve? – James Black Nov 09 '10 at 16:45
5 Answers
In order to retain the order you must try to order the list before passing it to foreach loop since by default the Parallel.Foreach treats the list as unordered.
Example :
Parallel.ForEach(
list.AsParallel().AsOrdered(),
(listItems) => {<operations that you need to do>});

- 165
- 1
- 7
So you have a statement that looks something like this? (based on your comments above).
Parallel.Foreach(myData, ..., (d) =>
{
StringBuilder sb = new StringBuilder();
sb.Append(d);
// WriteLine sb?
});
There are a number of issues with this approach.
- Neither
Parallel.For
orParallel.ForEach
will guarantee that your access to the contents ofmyData
are accessed in any particular order. - if you are a method on Console or a shared
StringBuilder
to either output the results or build up a complete string then you are probably blocking on a shared resource, effectively serializing parts of your parallel loop.
It's hard to say more without seeing a concrete example of your code. Depending on what you are doing you might be able to use the order preservation AsOrdered()
in PLINQ to get where you want.
See this MSDN Resource and
Ordered PLINQ ForAll
This will allow you to return an ordered result set, based on the input order but not guarentee the ordering of the actual processing. However if parallel query is blocking on a call within the body you're unlikely to get good performance.

- 1
- 1

- 13,575
- 1
- 42
- 75
Did this as an extension method
public static IEnumerable<T1> OrderedParallel<T, T1>(this IEnumerable<T> list, Func<T, T1> action)
{
var unorderedResult = new ConcurrentBag<(long, T1)>();
Parallel.ForEach(list, (o, state, i) =>
{
unorderedResult.Add((i, action.Invoke(o)));
});
var ordered = unorderedResult.OrderBy(o => o.Item1);
return ordered.Select(o => o.Item2);
}
use like:
var result = input.OrderedParallel(o => YourFunction(o));
Hope this will save you some time.

- 58,075
- 31
- 238
- 265
-
How to use it? When I put OrderedParallel on List
collection I get the error The type arguments for method 'IEnumerable – Tomas Jun 14 '22 at 12:13OrderedParallel (this IEnumerable , Func )' cannot be inferred from the usage. Try specifying the type arguments explicitly.
For anybody looking for a simple solution, I have posted 2 extension methods (one using PLINQ and one using Parallel.ForEach
) as part of an answer to the following question:

- 1
- 1

- 3,004
- 3
- 22
- 21
no, the ForEach is only to be used for conditions where order doesn't matter; try Parallel.For

- 15,717
- 17
- 76
- 109
-
-
I guess I should ask what you're trying to maintain order for -- is it like James Black said and you want to process the items in your IEnumerable? or is it that you want to make sure that what goes in comes back out in the same order? If it's the latter, they you should be fine with either a for or a foreach. If it's the former then you may not want to use the Parallel functions since operating on the items in sequence defeats the gain from operating them in parallel. – CodeMonkey1313 Nov 09 '10 at 16:58
-
I am using StringBuilder.WriteLine() inside my foreach, creating a row of data that is already sorted – Brian David Berman Nov 09 '10 at 17:16
-
depending on how you're sorting your data, you may be able to put the sort functionality into a parrallel parallel loop, though I'd recommend just using the built in .NET options for that. In the end, I don't think that a parallel loop is the right solution for you since you need sequential operations. – CodeMonkey1313 Nov 09 '10 at 18:39
-
This is incorrect. Parallel.For will not maintain ordering of the input data WRT to any output any more than Parallel.ForEach will. See my answer below. I have to down vote this because it's incorrect. – Ade Miller Mar 30 '11 at 12:34
-
Please edit Parallel.For to Parallel.ForAll. +1 to #Ade-Miller for this! – TamusJRoyce Mar 05 '15 at 20:18