/* From: Parallel Programming with Microsoft® .NET Design Patterns for Decomposition and Coordination on Multicore Architectures By Colin Campbell, Ralph Johnson, Ade Miller, Stephen Toub Publisher: Microsoft Press Released: August 2010 On-line: http://msdn.microsoft.com/en-us/library/ff963547.aspx Chapter on Parallel aggregation This example adds a partitioner to aggregating ForEach loop. */ using System; using System.Threading.Tasks; // using Parallel; using System.Collections.Generic; // for List using System.Collections.Concurrent; // for Partitioner class ParallelLoops { private static int Fib(int n) { if (n==0) { return 1; } else if (n==1) { return 1; } else { int n1 = Fib(n-1); int n2 = Fib(n-2); return n1+n2; } } private static void mkSequence(List seq, int m, int n) { if (m>n) { return; } else { seq.Add(m); mkSequence(seq, m+1, n); return; } } private int SomeComputation(int i) { return Fib(i); } private delegate void WorkerDelegate(); private static void TimeIt(WorkerDelegate worker) { DateTime startTime = DateTime.Now; DateTime stopTime = DateTime.Now; worker(); TimeSpan duration = stopTime - startTime; Console.WriteLine("Elapsed time: {0}", duration.ToString()); } public static void Main(string []args) { if (args.Length != 3) { // expect 1 arg: value to double System.Console.WriteLine("Usage: "); System.Console.WriteLine("k ... number of cores to use"); System.Console.WriteLine("m, n ... the range of values to apply Fib to; a good range isP: 35 39"); } else { int k = Convert.ToInt32(args[0]); int m = Convert.ToInt32(args[1]); int n = Convert.ToInt32(args[2]); int sum = 0; object lockObject = new { }; // any non-null object will do as lock // int[] fibs = new int[n]; List seq = new List(); mkSequence(seq, m, n); /* Parallel version, using only 2 tasks */ System.Console.WriteLine("Running Parallel Foreach, with aggregation, over sequence {0} on {1} cores", seq.ToString(), k); // var options = new ParallelOptions() { MaxDegreeOfParallelism = k}; int size = seq.Count / k; // make a partition large enough to feed k cores var rangePartitioner = Partitioner.Create(0, seq.Count, size); TimeIt(() => { Parallel.ForEach( // The input intervals rangePartitioner, // The local initial partial result () => 0, // The loop body for each interval (range, loopState, initialValue) => { // a *sequential* loop to increas the granularity of the parallelism int partialSum = initialValue; for (int i = range.Item1; i < range.Item2; i++) { partialSum += Fib(seq[i]); } return partialSum; }, // The final step of each local context (localPartialSum) => { // Use lock to enforce serial access to shared result lock (lockObject) { sum += localPartialSum; } }); }); Console.WriteLine("Sum of Fib({0}) .. Fib({1}) = {2}", m, n, sum); } } }