static ParallelLoopResult ForEach <TSource, TLocal> (Func <int, IList <IEnumerator <TSource> > > enumerable, ParallelOptions options, Func <TLocal> init, Func <TSource, ParallelLoopState, TLocal, TLocal> action, Action <TLocal> destruct) { int num = Math.Min(GetBestWorkerNumber(), options != null && options.MaxDegreeOfParallelism != -1 ? options.MaxDegreeOfParallelism : int.MaxValue); Task[] tasks = new Task[num]; ParallelLoopState.ExternalInfos infos = new ParallelLoopState.ExternalInfos(); ConcurrentBag <TSource> bag = new ConcurrentBag <TSource> (); const int bagCount = 5; IList <IEnumerator <TSource> > slices = enumerable(num); int sliceIndex = 0; Action workerMethod = delegate { IEnumerator <TSource> slice = slices[Interlocked.Increment(ref sliceIndex) - 1]; TLocal local = (init != null) ? init() : default(TLocal); ParallelLoopState state = new ParallelLoopState(tasks, infos); try { bool cont = true; TSource element; while (cont) { if (infos.IsStopped.Value) { return; } if (options != null && options.CancellationToken.IsCancellationRequested) { state.Stop(); return; } for (int i = 0; i < bagCount && (cont = slice.MoveNext()); i++) { bag.Add(slice.Current); } for (int i = 0; i < bagCount && bag.TryTake(out element); i++) { if (infos.IsStopped.Value) { return; } if (options != null && options.CancellationToken.IsCancellationRequested) { state.Stop(); return; } local = action(element, state, local); } } while (bag.TryTake(out element)) { if (infos.IsStopped.Value) { return; } if (options != null && options.CancellationToken.IsCancellationRequested) { state.Stop(); return; } local = action(element, state, local); } } finally { if (destruct != null) { destruct(local); } } }; if (options != null && options.TaskScheduler != null) { InitTasks(tasks, workerMethod, num, options.TaskScheduler); } else { InitTasks(tasks, workerMethod, num); } try { Task.WaitAll(tasks); } catch { HandleExceptions(tasks, infos); } return(new ParallelLoopResult(infos.LowestBreakIteration, !(infos.IsStopped.Value || infos.IsExceptional))); }
public static ParallelLoopResult For <TLocal> (int from, int to, ParallelOptions options, Func <TLocal> init, Func <int, ParallelLoopState, TLocal, TLocal> action, Action <TLocal> destruct) { if (action == null) { throw new ArgumentNullException("action"); } // Number of task to be launched (normally == Env.ProcessorCount) int num = Math.Min(GetBestWorkerNumber(), options != null && options.MaxDegreeOfParallelism != -1 ? options.MaxDegreeOfParallelism : int.MaxValue); // Integer range that each task process int step = Math.Min(5, (to - from) / num); if (step <= 0) { step = 1; } // Each worker put the indexes it's responsible for here // so that other worker may steal if they starve. ConcurrentBag <int> bag = new ConcurrentBag <int> (); Task[] tasks = new Task [num]; ParallelLoopState.ExternalInfos infos = new ParallelLoopState.ExternalInfos(); int currentIndex = from; Action workerMethod = delegate { int index, actual; TLocal local = (init == null) ? default(TLocal) : init(); ParallelLoopState state = new ParallelLoopState(tasks, infos); try { while ((index = Interlocked.Add(ref currentIndex, step) - step) < to) { if (infos.IsStopped.Value) { return; } if (options != null && options.CancellationToken.IsCancellationRequested) { state.Stop(); return; } for (int i = index; i < to && i < index + step; i++) { bag.Add(i); } for (int i = index; i < to && i < index + step && bag.TryTake(out actual); i++) { if (infos.IsStopped.Value) { return; } if (options != null && options.CancellationToken.IsCancellationRequested) { state.Stop(); return; } if (infos.LowestBreakIteration != null && infos.LowestBreakIteration > actual) { return; } state.CurrentIteration = actual; local = action(actual, state, local); } } while (bag.TryTake(out actual)) { if (infos.IsStopped.Value) { return; } if (options != null && options.CancellationToken.IsCancellationRequested) { state.Stop(); return; } if (infos.LowestBreakIteration != null && infos.LowestBreakIteration > actual) { continue; } state.CurrentIteration = actual; local = action(actual, state, local); } } finally { if (destruct != null) { destruct(local); } } }; if (options != null && options.TaskScheduler != null) { InitTasks(tasks, workerMethod, num, options.TaskScheduler); } else { InitTasks(tasks, workerMethod, num); } try { Task.WaitAll(tasks); } catch { HandleExceptions(tasks, infos); } return(new ParallelLoopResult(infos.LowestBreakIteration, !(infos.IsStopped.Value || infos.IsExceptional))); }