Пример #1
0
        static void HandleExceptions(IEnumerable <Task> tasks, ParallelLoopState.ExternalInfos infos)
        {
            List <Exception> exs = new List <Exception> ();

            foreach (Task t in tasks)
            {
                if (t.Exception != null)
                {
                    exs.Add(t.Exception);
                }
            }

            if (exs.Count > 0)
            {
                if (infos != null)
                {
                    infos.IsExceptional = true;
                }

                throw new AggregateException(exs).Flatten();
            }
        }
Пример #2
0
        public static ParallelLoopResult For <TLocal> (int fromInclusive,
                                                       int toExclusive,
                                                       ParallelOptions parallelOptions,
                                                       Func <TLocal> localInit,
                                                       Func <int, ParallelLoopState, TLocal, TLocal> body,
                                                       Action <TLocal> localFinally)
        {
            if (body == null)
            {
                throw new ArgumentNullException("body");
            }
            if (localInit == null)
            {
                throw new ArgumentNullException("localInit");
            }
            if (localFinally == null)
            {
                throw new ArgumentNullException("localFinally");
            }
            if (parallelOptions == null)
            {
                throw new ArgumentNullException("options");
            }
            if (fromInclusive >= toExclusive)
            {
                return(new ParallelLoopResult(null, true));
            }

            // Number of task toExclusive be launched (normally == Env.ProcessorCount)
            int step;
            int num = GetBestWorkerNumber(fromInclusive, toExclusive, parallelOptions, out step);

            Task[] tasks = new Task [num];

            StealRange[] ranges = new StealRange[num];
            for (int i = 0; i < num; i++)
            {
                ranges[i] = new StealRange(fromInclusive, i, step);
            }

            ParallelLoopState.ExternalInfos infos = new ParallelLoopState.ExternalInfos();

            int currentIndex = -1;

            Action workerMethod = delegate {
                int        localWorker = Interlocked.Increment(ref currentIndex);
                StealRange range       = ranges[localWorker];
                int        index       = range.V64.Actual;
                int        stopIndex   = localWorker + 1 == num ? toExclusive : Math.Min(toExclusive, index + step);
                TLocal     local       = localInit();

                ParallelLoopState state = new ParallelLoopState(infos);
                CancellationToken token = parallelOptions.CancellationToken;

                try {
                    for (int i = index; i < stopIndex;)
                    {
                        if (infos.IsStopped)
                        {
                            return;
                        }

                        token.ThrowIfCancellationRequested();

                        if (i >= stopIndex - range.V64.Stolen)
                        {
                            break;
                        }

                        if (infos.LowestBreakIteration != null && infos.LowestBreakIteration > i)
                        {
                            return;
                        }

                        state.CurrentIteration = i;
                        local = body(i, state, local);

                        if (i + 1 >= stopIndex - range.V64.Stolen)
                        {
                            break;
                        }

                        range.V64.Actual = ++i;
                    }

                    bool sixtyfour = IntPtr.Size == 8;                     // Environment.Is64BitProcess;

                    // Try toExclusive steal fromInclusive our right neighbor (cyclic)
                    int len = num + localWorker;
                    for (int sIndex = localWorker + 1; sIndex < len; ++sIndex)
                    {
                        int extWorker = sIndex % num;
                        range = ranges[extWorker];

                        stopIndex = extWorker + 1 == num ? toExclusive : Math.Min(toExclusive, fromInclusive + (extWorker + 1) * step);
                        int stolen = -1;

                        do
                        {
                            do
                            {
                                long         old;
                                StealValue64 val = new StealValue64();

                                old       = sixtyfour ? range.V64.Value : Interlocked.CompareExchange(ref range.V64.Value, 0, 0);
                                val.Value = old;

                                if (val.Actual >= stopIndex - val.Stolen - 2)
                                {
                                    goto next;
                                }
                                stolen = (val.Stolen += 1);

                                if (Interlocked.CompareExchange(ref range.V64.Value, val.Value, old) == old)
                                {
                                    break;
                                }
                            } while (true);

                            stolen = stopIndex - stolen;

                            if (stolen > range.V64.Actual)
                            {
                                local = body(stolen, state, local);
                            }
                            else
                            {
                                break;
                            }
                        } while (true);

next:
                        continue;
                    }
                } finally {
                    localFinally(local);
                }
            };

            InitTasks(tasks, num, workerMethod, parallelOptions);

            try {
                Task.WaitAll(tasks);
            } catch {
                HandleExceptions(tasks, infos);
            }

            return(new ParallelLoopResult(infos.LowestBreakIteration, !(infos.IsStopped || infos.IsExceptional)));
        }
Пример #3
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)
        {
            if (enumerable == null)
            {
                throw new ArgumentNullException("source");
            }
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }
            if (init == null)
            {
                throw new ArgumentNullException("init");
            }
            if (destruct == null)
            {
                throw new ArgumentNullException("destruct");
            }

            int num = Math.Min(GetBestWorkerNumber(options.TaskScheduler),
                               options != null && options.MaxDegreeOfParallelism != -1 ? options.MaxDegreeOfParallelism : int.MaxValue);

            Task[] tasks = new Task[num];
            ParallelLoopState.ExternalInfos infos = new ParallelLoopState.ExternalInfos();

            SimpleConcurrentBag <TSource> bag = new SimpleConcurrentBag <TSource> (num);
            const int bagCount = 5;

            IList <IEnumerator <TSource> > slices = enumerable(num);

            int sliceIndex = -1;

            Action workerMethod = delegate {
                IEnumerator <TSource> slice = slices[Interlocked.Increment(ref sliceIndex)];

                TLocal            local = init();
                ParallelLoopState state = new ParallelLoopState(infos);
                int workIndex           = bag.GetNextIndex();
                CancellationToken token = options.CancellationToken;

                try {
                    bool    cont = true;
                    TSource element;

                    while (cont)
                    {
                        if (infos.IsStopped || infos.IsBroken.Value)
                        {
                            return;
                        }

                        token.ThrowIfCancellationRequested();

                        for (int i = 0; i < bagCount && (cont = slice.MoveNext()); i++)
                        {
                            bag.Add(workIndex, slice.Current);
                        }

                        for (int i = 0; i < bagCount && bag.TryTake(workIndex, out element); i++)
                        {
                            if (infos.IsStopped)
                            {
                                return;
                            }

                            token.ThrowIfCancellationRequested();

                            local = action(element, state, local);
                        }
                    }

                    while (bag.TrySteal(workIndex, out element))
                    {
                        token.ThrowIfCancellationRequested();

                        local = action(element, state, local);

                        if (infos.IsStopped || infos.IsBroken.Value)
                        {
                            return;
                        }
                    }
                } finally {
                    destruct(local);
                }
            };

            InitTasks(tasks, num, workerMethod, options);

            try {
                Task.WaitAll(tasks);
            } catch {
                HandleExceptions(tasks, infos);
            }

            return(new ParallelLoopResult(infos.LowestBreakIteration, !(infos.IsStopped || infos.IsExceptional)));
        }
Пример #4
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");
            }
            if (init == null)
            {
                throw new ArgumentNullException("localInit");
            }
            if (destruct == null)
            {
                throw new ArgumentNullException("localFinally");
            }
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }
            if (from >= to)
            {
                return(new ParallelLoopResult(null, true));
            }

            // Number of task to be launched (normally == Env.ProcessorCount)
            int step;
            int num = GetBestWorkerNumber(from, to, options, out step);

            Task[] tasks = new Task [num];

            StealRange[] ranges = new StealRange[num];
            for (int i = 0; i < num; i++)
            {
                ranges[i] = new StealRange(from, i, step);
            }

            ParallelLoopState.ExternalInfos infos = new ParallelLoopState.ExternalInfos();

            int currentIndex = -1;

            Action workerMethod = delegate {
                int        localWorker = Interlocked.Increment(ref currentIndex);
                StealRange range       = ranges[localWorker];
                int        index       = range.Actual;
                int        stopIndex   = localWorker + 1 == num ? to : Math.Min(to, index + step);
                TLocal     local       = init();

                ParallelLoopState state = new ParallelLoopState(infos);
                CancellationToken token = options.CancellationToken;

                try {
                    for (int i = index; i < stopIndex; range.Actual = ++i)
                    {
                        if (infos.IsStopped)
                        {
                            return;
                        }

                        token.ThrowIfCancellationRequested();

                        if (infos.LowestBreakIteration != null && infos.LowestBreakIteration > i)
                        {
                            return;
                        }

                        state.CurrentIteration = i;
                        local = action(i, state, local);
                        if (i >= stopIndex - range.Stolen)
                        {
                            break;
                        }
                    }

                    // Try to steal from our right neighbor (cyclic)
                    int len = num + localWorker;
                    for (int sIndex = localWorker + 1; sIndex < len; ++sIndex)
                    {
                        int extWorker = sIndex % num;
                        range = ranges[extWorker];

                        stopIndex = extWorker + 1 == num ? to : Math.Min(to, from + (extWorker + 1) * step);

                        int stolen;
                        do
                        {
                            stolen = range.Stolen;
                            if (stopIndex - stolen > range.Actual)
                            {
                                goto next;
                            }
                        } while (Interlocked.CompareExchange(ref range.Stolen, stolen + 1, stolen) != stolen);

                        stolen = stopIndex - stolen - 1;

                        if (stolen > range.Actual)
                        {
                            local = action(stolen, state, local);
                        }

next:
                        continue;
                    }
                } finally {
                    destruct(local);
                }
            };

            InitTasks(tasks, num, workerMethod, options);

            try {
                Task.WaitAll(tasks);
            } catch {
                HandleExceptions(tasks, infos);
            }

            return(new ParallelLoopResult(infos.LowestBreakIteration, !(infos.IsStopped || infos.IsExceptional)));
        }