开发者

Parallel.Foreach maintain collection order?

开发者 https://www.devze.com 2023-01-24 00:45 出处:网络
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

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.

  1. Neither Parallel.For or Parallel.ForEach will guarantee that your access to the contents of myData are accessed in any particular order.
  2. 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

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号