c\#병렬 계산

병렬 계산 부분
마이크로소프트 의 쓰기,System.Threading.Tasks.:Parallel 클래스 를 사용 하여 병렬 순환 과 지역 에 대한 지원 을 제공 합 니 다.저희 가 사용 할 방법 은 For,Foreach,Invoke 입 니 다.
간단 하 다
우선 순환 에 사용 할 List 를 초기 화 합 니 다.여기 서 10 번 순환 합 니 다.(다음 코드 는 모두 이 표준 에 따라 순환 합 니 다)

            Program.Data = new List<int>();
            for (int i = 0; i < 10; i++)
            {
                Data.Add(i);
            }
다음은 for,foreach,병렬 For,병렬 Foreach 등 네 가지 방법 을 정의 합 니 다.그들의 운행 시간 을 측정 한다.

        /// <summary>
        ///         
        /// </summary>
        public bool ShowProcessExecution = false;
        /// <summary>
        ///       for
        /// </summary>
        private void Demo1()
        {
            List<int> data = Program.Data;
            DateTime dt1 = DateTime.Now;
            for (int i = 0; i < data.Count; i++)
            {
                Thread.Sleep(500);
                if (ShowProcessExecution)
                    Console.WriteLine(data[i]);
            }
            DateTime dt2 = DateTime.Now;
            Console.WriteLine("    For    :{0}  。", (dt2 - dt1).TotalMilliseconds);
        }
        /// <summary>
        ///       foreach
        /// </summary>
        private void Demo2()
        {
            List<int> data = Program.Data;
            DateTime dt1 = DateTime.Now;
            foreach (var i in data)
            {
                Thread.Sleep(500);
                if (ShowProcessExecution)
                    Console.WriteLine(i);
            }
            DateTime dt2 = DateTime.Now;
            Console.WriteLine("    For    :{0}  。", (dt2 - dt1).TotalMilliseconds);
        }
        /// <summary>
        ///       For
        /// </summary>
        private void Demo3()
        {
            List<int> data = Program.Data;
            DateTime dt1 = DateTime.Now;
            Parallel.For(0, data.Count, (i) =>
            {
                Thread.Sleep(500);
                if (ShowProcessExecution)
                    Console.WriteLine(data[i]);
            });
            DateTime dt2 = DateTime.Now;
            Console.WriteLine("    For    :{0}  。", (dt2 - dt1).TotalMilliseconds);
        }
        /// <summary>
        ///       ForEach
        /// </summary>
        private void Demo4()
        {
            List<int> data = Program.Data;
            DateTime dt1 = DateTime.Now;
            Parallel.ForEach(data, (i) =>
            {
                Thread.Sleep(500);
                if (ShowProcessExecution)
                    Console.WriteLine(i);
            });
            DateTime dt2 = DateTime.Now;
            Console.WriteLine("    ForEach    :{0}  。", (dt2 - dt1).TotalMilliseconds);
        }
다음은 실행 결과 입 니 다.

여기 서 우 리 는 병행 순환 이 집행 효율 에서 의 장점 을 알 수 있다.
결론 1:한 배열 안의 모든 항목 을 단독으로 처리 할 때 병행 순환 방식 을 선택 하여 집행 효율 을 높 일 수 있다.
원리 1:병렬 계 산 된 스 레 드 오픈 은 천천히 열 리 고 스 레 드 수량 1,2,4,8 천천히 증가 합 니 다.(자세 하지 않 습 니 다.PLinq 최대 64 개의 스 레 드 입 니 다.이것 도 64 일 수 있 습 니 다)
2.병렬 순환 의 중단 과 점프
        순환 을 할 때 가끔 순환 을 중단 하거나 순환 을 뛰 어 넘 어야 한다.다음은 순환 을 뛰 어 넘 는 두 가지 방법 입 니 다.Stop 과 Break,LoopState 는 순환 상태의 매개 변수 입 니 다.

        /// <summary>
        ///   Stop
        /// </summary>
        private void Demo5()
        {
            List<int> data = Program.Data;
            Parallel.For(0, data.Count, (i, LoopState) =>
            {
                if (data[i] > 5)
                    LoopState.Stop();
                Thread.Sleep(500);
                Console.WriteLine(data[i]);
            });
            Console.WriteLine("Stop    。");
        }
        /// <summary>
        ///   Break
        /// </summary>
        private void Demo6()
        {
            List<int> data = Program.Data;
            Parallel.ForEach(data, (i, LoopState) =>
            {
                if (i > 5)
                    LoopState.Break();
                Thread.Sleep(500);
                Console.WriteLine(i);
            });
            Console.WriteLine("Break    。");
        }
        실행 결 과 는 다음 과 같 습 니 다.

결론 2:Stop 을 사용 하면 즉시 순환 을 중단 하고 Break 를 사용 하면 조건 에 맞 는 모든 항목 을 수행 합 니 다.
3.병렬 순환 에서 배열/집합 에 항목 추가
        위의 응용 장면 은 사실 매우 많은 것 이 아니다.왜냐하면 한 배열 안의 자원 을 옮 겨 다 니 기 위해 서 이다.우 리 는 자원 을 옮 겨 다 니 며 우리 가 필요 로 하 는 것 을 찾기 위해 서 이다.그럼 계속 보 세 요.
다음은 우리 가 일반적으로 생각 하 는 표기 법 이다.

        private void Demo7()
        {
            List<int> data = new List<int>();
            Parallel.For(0, Program.Data.Count, (i) =>
            {
                if (Program.Data[i] % 2 == 0)
                    data.Add(Program.Data[i]);
            });
            Console.WriteLine("    For.");
        }
        private void Demo8()
        {
            List<int> data = new List<int>();
            Parallel.ForEach(Program.Data, (i) =>
            {
                if (Program.Data[i] % 2 == 0)
                    data.Add(Program.Data[i]);
            });
            Console.WriteLine("    ForEach.");
        }
보기 에는 문제 가 없 을 것 같 지만,우 리 는 여러 번 실행 한 후에 가끔 다음 과 같은 오류 가 발생 할 수 있다 는 것 을 알 게 될 것 이다.

이것 은 List 가 비 스 레 드 안전 한 클래스 이기 때문에 System.collections.Concurrent 네 임 스페이스 의 유형 을 사용 하여 체 내 순환 을 병행 해 야 합 니 다.
종류
설명 하 다.
BlockingCollection
IProducer ConsumerCollection의 라인 안전 집합 을 실현 하기 위해 저지 와 제한 기능 을 제공 합 니 다.
ConcurrentBag
대상 의 스 레 드 안전 을 나타 내 는 무질서 한 집합.
ConcurrentDictionary
여러 스 레 드 가 동시에 접근 할 수 있 는 키 값 이 맞 는 스 레 드 안전 집합 을 표시 합 니 다.
ConcurrentQueue
안전 한 라인 을 나타 내 는 선진 선 출(FIFO)집합.
ConcurrentStack
스 레 드 안전 을 나타 내 는 후진 선 출(LIFO)집합.
OrderablePartitioner
정렬 가능 한 데이터 원본 을 여러 파 티 션 으로 나 누 는 특정한 방식 을 나타 낸다.
Partitioner
배열,목록,매 거 진 항목 에 대한 일반적인 파 티 션 정책 을 제공 합 니 다.
Partitioner
하나의 데이터 원본 을 여러 개의 구역 으로 나 누 는 특정한 방식 을 나타 낸다.
그러면 우리 위의 코드 는 ConcurrentQueue 와 ConcurrentStack 의 가장 기본 적 인 조작 으로 수정 할 수 있 습 니 다.

        /// <summary>
        ///          ,     5   
        /// </summary>
        private void Demo7()
        {
            ConcurrentQueue<int> data = new ConcurrentQueue<int>();
            Parallel.For(0, Program.Data.Count, (i) =>
            {
                if (Program.Data[i] % 2 == 0)
                    data.Enqueue(Program.Data[i]);//          
            });
            int R;
            while (data.TryDequeue(out R))//           
            {
                Console.WriteLine(R);
            }
            Console.WriteLine("    For.");
        }
        /// <summary>
        ///          
        /// </summary>
        private void Demo8()
        {
            ConcurrentStack<int> data = new ConcurrentStack<int>();
            Parallel.ForEach(Program.Data, (i) =>
            {
                if (Program.Data[i] % 2 == 0)
                    data.Push(Program.Data[i]);//       
            });
            int R;
            while (data.TryPop(out R))//      
            {
                Console.WriteLine(R);
            }
            Console.WriteLine("    ForEach.");
        }
ok,여기 서 하나의 서열 로 돌아 가 는 문제 도 해결 되 었 습 니 다.
결론 3:병렬 순환 에서 반복 되 는 대상 은 thread-safe(스 레 드 안전)이 어야 합 니 다.집합 클래스 의 스 레 드 보안 대상 은 모두 System.collections.Concurrent 네 임 스페이스 에 있 습 니 다.
4.집합 연산 결과/부분 변 수 를 포함 한 병렬 순환 을 되 돌려 줍 니 다.
        순환 을 사용 할 때 도 교체 가 자주 사용 된다.그러면 병행 순환 에서 국부 변 수 를 포함 하 는 순환 이 라 고 한다.아래 의 코드 에서 상세 하 게 설명 하면 여 기 는 잔소리 하지 않 겠 습 니 다.

        /// <summary>
        ///          For  
        /// </summary>
        private void Demo9()
        {
            List<int> data = Program.Data;
            long total = 0;
            //        long             
            Parallel.For<long>(0,           // For     
                data.Count,                 // For     
                () => 0,                    //           (long),     subtotal   
                (i, LoopState, subtotal) => //             ,i     ,LoopState     ,subtotal      
                {
                    subtotal += data[i];    //       
                    return subtotal;        //           
                },
                (finalResult) => Interlocked.Add(ref total, finalResult) //              ,           
                );
            Console.WriteLine(total);
        }
        /// <summary>
        ///          ForEach  
        /// </summary>
        private void Demo10()
        {
            List<int> data = Program.Data;
            long total = 0;
            Parallel.ForEach<int, long>(data, //         
                () => 0,                      //           (long),     subtotal   
                (i, LoopState, subtotal) =>   //             ,i     ,LoopState     ,subtotal      
                {
                    subtotal += i;            //       
                    return subtotal;          //           
                },
                (finalResult) => Interlocked.Add(ref total, finalResult) //              ,           
                );
            Console.WriteLine(total);
        }
결론 4:병행 순환 중의 교 체 는 확실히 사람 을 상하 게 한다.코드 가 너무 어려워 요.
5.PLinq(Linq 의 병렬 계산)
           For 와 Foreach 의 병행 컴 퓨 팅 향 연 을 소 개 했 고 마이크로소프트 도 Linq 에 병행 컴 퓨 팅 을 넣 는 것 을 잊 지 않 았 다.다음은 Linq 의 병렬 계산 을 소개 합 니 다.
4.0 에서 System.Linq 네 임 스페이스 에 다음 과 같은 몇 가지 새로운 종 류 를 추가 하 였 습 니 다.
종류
설명 하 다.
ParallelEnumerable
ParallelQuery{TSource}의 대상 을 조회 하 는 방법 을 제공 합 니 다.Enumerable 의 병렬 등가 항목 입 니 다.
ParallelQuery
병렬 서열 을 나타 낸다.
ParallelQuery
병렬 서열 을 나타 낸다.
원리 2:PLinq 최대 64 개 스 레 드 오픈
원리 3:PLinq 는 병렬 계산 이 가능 한 지 스스로 판단 하고,그렇지 않 으 면 순차 모드 로 작 동 합 니 다.
원리 4:PLinq 는 비 싼 병렬 알고리즘 이나 원가 가 낮은 순서 알고리즘 사 이 를 선택 합 니 다.기본적으로 순서 알고리즘 을 선택 합 니 다.
ParallelEnumerable 에서 제공 하 는 병행 화 방법
병렬 Enumerable 연산 자
설명 하 다.
AsParallel()
PLINQ 의 입구 점.가능 하 다 면 조 회 를 병행 해 야 할 나머지 부분 을 지정 합 니 다.
AsSequential()
지정 한 조회 의 나머지 부분 은 비 병렬 LINQ 조회 처럼 순서대로 실행 해 야 한다.
AsOrdered()
PLINQ 는 orderby 자 구 를 사용 하여 정렬 을 변경 할 때 까지 조회 의 나머지 부분의 원본 정렬 을 유지 해 야 합 니 다.
AsUnordered()
검색 의 나머지 부분 을 지정 한 PLINQ 는 원본 시퀀스 의 정렬 을 유지 할 필요 가 없습니다.
WithCancellation()
PLINQ 를 지정 하면 취소 요청 시 제 공 된 취소 표시 와 실행 취소 상 태 를 정기 적 으로 감시 해 야 합 니 다.
WithDegreeOfParallelism()
병렬 검색 에 사용 할 프로세서 의 최대 수 를 지정 합 니 다.
WithMergeOptions()
PLINQ 가 병렬 결 과 를 사용 스 레 드 의 한 시퀀스 로 통합 하 는 방법 에 대한 힌트 를 제공 합 니 다.
WithExecutionMode()
PLINQ 가 검색 을 어떻게 병행 해 야 하 는 지 지정 합 니 다.(기본 동작 이 순서대로 실행 되 더 라 도)
ForAll()
다 중 스 레 드 매 거 진 방법 은 순환 방문 조회 결과 와 달리 사용자 스 레 드 로 먼저 통합 되 지 않 은 상태 에서 병행 처리 결 과 를 허용 합 니 다.
Aggregate()적재량
PLINQ 의 유일한 리 셋 에 대해 서 는 스 레 드 로 컬 파 티 션 의 중간 집합 과 모든 파 티 션 결 과 를 통합 하 는 최종 집합 함 수 를 사용 합 니 다.
다음은 PLinq 의 간단 한 코드 입 니 다.

        /// <summary>
        /// PLinq  
        /// </summary>
        private void Demo11()
        {
            var source = Enumerable.Range(1, 10000);
            //     source      
            var evenNums = from num in source.AsParallel().AsOrdered()
                       where num % 2 == 0
                       select num;
            //ForAll   
            ConcurrentBag<int> concurrentBag = new ConcurrentBag<int>();
            var query = from num in source.AsParallel()
                        where num % 10 == 0
                        select num;
            query.ForAll((e) => concurrentBag.Add(e * e));
        }
위의 코드 에서 ForAll,ForAll 과 foreach 의 차 이 는 다음 과 같다.

이상 은 c\#병렬 컴 퓨 팅 에 대한 상세 한 내용 입 니 다.c\#병렬 컴 퓨 팅 에 관 한 자 료 는 다른 관련 글 을 주목 하 세 요!

좋은 웹페이지 즐겨찾기