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();