Beispiel #1
0
        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)));
        }
Beispiel #2
0
        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)));
        }