2

Inspired by Clojure 1.5's reducers library, I've been playing with making PLINQ's ParallelEnumerable.Aggregate() method behave the same way. For the most part, it very straightforwardly does.

There's one possible behavior difference that I suspect may exist, though. In Igor Ostrovsky's blog post about the 2007 CTP, he claims that combineAccumulatorsFunc has to be commutative. The modern documentation doesn't seem to say anything about it having to be commutative, and I haven't been able to force it to do anything that depends on commutativity, but I also haven't been able to force it to do anything that depends on associativity.

Main question: Are the semantics of combineAccumulatorsFunc defined anywhere? Even if not, am I going to be okay assuming that it may be called associatively but not commutatively?

I'm using the following LINQPad snippet to try to cause out-of-order combineAccumulatorsFunc invocations:

ParallelEnumerable.Range(0,1000000).AsUnordered().WithDegreeOfParallelism(10).
        WithExecutionMode(ParallelExecutionMode.ForceParallelism).
        Aggregate<int,IImmutableList<int>,IEnumerable<int>>(
  () => { Thread.Sleep(new Random().Next(5000)); return ImmutableList<int>.Empty; },
  (L,n) => n % 2 == 0 ? L.Add(n) : L,
  (L1,L2) => {new {L1 = L1.First(),L2 = L2.First()}.Dump("partition"); return L1.Concat(L2).ToImmutableList();},
  x => x.AsEnumerable()
).Dump();
4

0 回答 0