/// <summary> /// Executes a for loop in which iterations may run in parallel. /// </summary> /// <param name="fromInclusive">The start index, inclusive.</param> /// <param name="toExclusive">The end index, exclusive.</param> /// <param name="rangeSize">The partition size for splitting work into smaller pieces.</param> /// <param name="body">The body to be invoked for each iteration range.</param> public static void For(int fromInclusive, int toExclusive, int rangeSize, Action <int, int> body) { if (body == null) { throw new ArgumentNullException("body"); } if (fromInclusive < 0) { throw new ArgumentOutOfRangeException("fromInclusive"); } if (fromInclusive > toExclusive) { throw new ArgumentOutOfRangeException("toExclusive"); } if (rangeSize < 1) { throw new ArgumentOutOfRangeException("rangeSize"); } var length = toExclusive - fromInclusive; // Special case: nothing to do if (length <= 0) { return; } // Special case: not worth to parallelize, inline if (Control.MaxDegreeOfParallelism < 2 || (rangeSize * 2) > length) { body(fromInclusive, toExclusive); return; } // Common case Parallel.ForEach( Partitioner.Create(fromInclusive, toExclusive, rangeSize), CreateParallelOptions(), range => body(range.Item1, range.Item2)); }
/// <summary> /// Selects an item (such as Max or Min). /// </summary> /// <param name="array">The array to iterate over.</param> /// <param name="select">The function to select items over a subset.</param> /// <param name="reduce">The function to select the item of selection from the subsets.</param> /// <returns>The selected value.</returns> public static TOut Aggregate <T, TOut>(T[] array, Func <int, T, TOut> select, Func <TOut[], TOut> reduce) { if (select == null) { throw new ArgumentNullException("select"); } if (reduce == null) { throw new ArgumentNullException("reduce"); } // Special case: no action if (array == null || array.Length == 0) { return(reduce(new TOut[0])); } // Special case: single action, inline if (array.Length == 1) { return(reduce(new[] { select(0, array[0]) })); } // Special case: straight execution without parallelism if (Control.MaxDegreeOfParallelism < 2) { var mapped = new TOut[array.Length]; for (int k = 0; k < mapped.Length; k++) { mapped[k] = select(k, array[k]); } return(reduce(mapped)); } // Common case var intermediateResults = new List <TOut>(); var syncLock = new object(); Parallel.ForEach( Partitioner.Create(0, array.Length), CreateParallelOptions(), () => new List <TOut>(), (range, loop, localData) => { var mapped = new TOut[range.Item2 - range.Item1]; for (int k = 0; k < mapped.Length; k++) { mapped[k] = select(k + range.Item1, array[k + range.Item1]); } localData.Add(reduce(mapped)); return(localData); }, localResult => { lock (syncLock) { intermediateResults.Add(reduce(localResult.ToArray())); } }); return(reduce(intermediateResults.ToArray())); }
/// <summary> /// Selects an item (such as Max or Min). /// </summary> /// <param name="fromInclusive">Starting index of the loop.</param> /// <param name="toExclusive">Ending index of the loop</param> /// <param name="select">The function to select items over a subset.</param> /// <param name="reduce">The function to select the item of selection from the subsets.</param> /// <returns>The selected value.</returns> public static T Aggregate <T>(int fromInclusive, int toExclusive, Func <int, T> select, Func <T[], T> reduce) { if (select == null) { throw new ArgumentNullException("select"); } if (reduce == null) { throw new ArgumentNullException("reduce"); } // Special case: no action if (fromInclusive >= toExclusive) { return(reduce(new T[0])); } // Special case: single action, inline if (fromInclusive == (toExclusive - 1)) { return(reduce(new[] { select(fromInclusive) })); } // Special case: straight execution without parallelism if (Control.MaxDegreeOfParallelism < 2) { var mapped = new T[toExclusive - fromInclusive]; for (int k = 0; k < mapped.Length; k++) { mapped[k] = select(k + fromInclusive); } return(reduce(mapped)); } // Common case var intermediateResults = new List <T>(); var syncLock = new object(); Parallel.ForEach( Partitioner.Create(fromInclusive, toExclusive), CreateParallelOptions(), () => new List <T>(), (range, loop, localData) => { var mapped = new T[range.Item2 - range.Item1]; for (int k = 0; k < mapped.Length; k++) { mapped[k] = select(k + range.Item1); } localData.Add(reduce(mapped)); return(localData); }, localResult => { lock (syncLock) { intermediateResults.Add(reduce(localResult.ToArray())); } }); return(reduce(intermediateResults.ToArray())); }