Parallel.Foreach maintain collection order?
Is there a way to gu开发者_如何学Carantee 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.
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>});
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.
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.
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:
Ordered PLINQ ForAll
no, the ForEach is only to be used for conditions where order doesn't matter; try Parallel.For
精彩评论