Exemple #1
0
        /// <summary>
        /// <paramref name="inputs"/> 시퀀스를 <paramref name="tranform"/> 함수를 이용하여 TOutput 수형의 시퀀스로 매핑합니다. 매핑 작업을 병렬로 수행합니다.
        /// </summary>
        /// <typeparam name="TInput">입력 데이타 수형</typeparam>
        /// <typeparam name="TOutput">반환 데이타 수형</typeparam>
        /// <param name="inputs">입력 데이타</param>
        /// <param name="parallelOptions">병렬 처리 옵션</param>
        /// <param name="tranform">입력을 출력으로 변환하는 함수</param>
        /// <returns>Mapping된 출력 데이타</returns>
        public static IList <TOutput> Map <TInput, TOutput>(IList <TInput> inputs, ParallelOptions parallelOptions,
                                                            Func <TInput, TOutput> tranform)
        {
            inputs.ShouldNotBeNull("inputs");
            parallelOptions.ShouldNotBeNull("parallelOptions");
            tranform.ShouldNotBeNull("transform");

            if (IsDebugEnabled)
            {
                log.Debug("수형[{0}]=>수형[{1}]으로 매핑함수를 이용하여 병렬 매핑을 수행합니다.", typeof(TInput).FullName, typeof(TOutput).FullName);
            }

            if (inputs.Count == 0)
            {
                return(new List <TOutput>());
            }

            var outputs  = new TOutput[inputs.Count];
            var syncLock = new object();

            // TODO: 범위로 나누어서 작업하는 것이 어떨까? 다만 False Sharing 문제로 더 느려질 수 있으니 확인해 봐야 한다.

            ForRange(0,
                     inputs.Count,
                     () => new KeyValuePair <TOutput[], int[]>(new TOutput[inputs.Count], new int[2]),
                     (from, to, loopstate, localPair) => {
                var localOutputs = localPair.Key;

                // 로컬 배열에 변환된 인스턴스를 저장합니다. False Sharing 문제를 해결하기 위해, 로컬 배열에 저장해야 합니다.
                for (var i = from; i < to; i++)
                {
                    localOutputs[i] = tranform(inputs[i]);
                }

                localPair.Value[0] = from;
                localPair.Value[1] = to;

                return(localPair);
            },
                     localPair => {
                var localOuputs = localPair.Key;

                var from = localPair.Value[0];
                var to   = localPair.Value[1];

                // 로컬 배열로부터 최종 배열로 값을 복사합니다.
                lock (syncLock)
                    Array.Copy(localOuputs, from, outputs, from, to - from);
            });

            return(outputs.ToList());
        }
        /// <summary>
        /// 특정 범위를 분할해서 병렬로 로컬 작업을 수행합니다 (병렬 작업을 너무 세분화 시키지 않고, 분할해서 작업하면 효과적이다.)
        /// </summary>
        /// <param name="fromInclusive">시작 인덱스</param>
        /// <param name="toExclusive">종료 인덱스</param>
        /// <param name="parallelOptions">병렬 실행 옵션</param>
        /// <param name="body">구간 단위의 실행을 담당하는 delegate</param>
        /// <returns></returns>
        public static ParallelLoopResult ForRange(long fromInclusive,
                                                  long toExclusive,
                                                  ParallelOptions parallelOptions,
                                                  Action <long, long, ParallelLoopState> body)
        {
            parallelOptions.ShouldNotBeNull("parallelOptions");
            body.ShouldNotBeNull("body");

            if (IsDebugEnabled)
            {
                log.Debug("특정 범위를 분할해서 병렬로 로컬 작업을 수행합니다. 구간=[{0},{1})", fromInclusive, toExclusive);
            }

            return(Parallel.ForEach(CreateRangePartition(fromInclusive, toExclusive),
                                    parallelOptions,
                                    (range, loopState) => body(range.Item1, range.Item2, loopState)));
        }
Exemple #3
0
        /// <summary>
        /// 컬렉션에서 검사자를 만족하는 요소들만 병렬로 필터링합니다.
        /// </summary>
        public static IList <T> Filter <T>(IList <T> inputs, ParallelOptions parallelOptions, Func <T, bool> predicate)
        {
            inputs.ShouldNotBeNull("inputs");
            parallelOptions.ShouldNotBeNull("parallelOptions");
            predicate.ShouldNotBeNull("predicate");

            if (IsDebugEnabled)
            {
                log.Debug("리스트를 병렬로 필터링을 수행합니다. 요소의 순서는 뒤바뀔 수 있습니다...");
            }

            var results = new List <T>(inputs.Count);

            // NOTE: 병렬 작업별로, 최대한 독립수행이 가능하도록 local value를 사용하여 병렬 작업을 합니다.
            //
            Parallel.For <IList <T> >(0,
                                      inputs.Count,
                                      parallelOptions,
                                      () => new List <T>(inputs.Count),
                                      (i, loop, localList) => {
                T item = inputs[i];
                if (predicate(item))
                {
                    localList.Add(item);
                }

                return(localList);
            },
                                      localList => {
                lock (results)
                    results.AddRange(localList);
            });

            results.TrimExcess();

            if (IsDebugEnabled)
            {
                log.Debug("리스트를 병렬로 필터링을 수행했습니다. 리스트 요소의 순서는 뒤바뀔 수 있습니다.");
            }

            return(results);
        }
        /// <summary>
        /// 특정 범위를 분할해서 병렬로 로컬 작업을 수행합니다 (병렬 작업을 너무 세분화 시키지 않고, 분할해서 작업하면 효과적이다.)
        /// </summary>
        /// <typeparam name="TLocal"></typeparam>
        /// <param name="fromInclusive">시작 인덱스</param>
        /// <param name="toExclusive">종료 인덱스</param>
        /// <param name="parallelOptions">병렬 실행 옵션</param>
        /// <param name="localInit">구간 단위의 초기화 값을 제공하는 delegate</param>
        /// <param name="localBody">구간 단위의 실행을 담당하는 delegate</param>
        /// <param name="localFinally">구간별 실행 결과 합치는 delegate</param>
        /// <returns></returns>
        public static ParallelLoopResult ForRange <TLocal>(long fromInclusive,
                                                           long toExclusive,
                                                           ParallelOptions parallelOptions,
                                                           Func <TLocal> localInit,
                                                           Func <long, long, ParallelLoopState, TLocal, TLocal> localBody,
                                                           Action <TLocal> localFinally)
        {
            parallelOptions.ShouldNotBeNull("parallelOptions");
            localInit.ShouldNotBeNull("localInit");
            localBody.ShouldNotBeNull("localBody");
            localFinally.ShouldNotBeNull("localFinally");

            if (IsDebugEnabled)
            {
                log.Debug("특정 범위를 분할해서 병렬로 로컬 작업을 수행합니다. 구간=[{0},{1})", fromInclusive, toExclusive);
            }

            return(Parallel.ForEach(CreateRangePartition(fromInclusive, toExclusive),
                                    parallelOptions,
                                    localInit,
                                    (range, loopState, x) => localBody(range.Item1, range.Item2, loopState, x),
                                    localFinally));
        }