c\#병렬 및 다 중 스 레 드 프로 그래 밍―Parallel 인식

다 핵 시대 가 도래 함 에 따라 병행 개발 은 점점 더 강력 한 위력 을 보 여 준다!병렬 프로그램 을 사용 하여 시스템 자원 을 충분히 이용 하여 프로그램의 성능 을 향상 시킨다..net 4.0 에서 마이크로소프트 는 우리 에 게 새로운 네 임 스페이스 를 제공 했다.System.Threading.Tasks.이 안 에는 병행 개발 에 관 한 것 이 많 습 니 다.오늘 첫 편 에 서 는 가장 기본 적 이 고 간단 한 인식 과 Parallel 을 소개 합 니 다.
1.Parallel 의 사용
Parallel 아래 에 자주 사용 하 는 세 가지 방법 이 있 습 니 다.invoke,For,ForEach.
1、Parallel.Invoke
이것 은 가장 간단 하고 가장 간결 하 게 직렬 코드 를 병렬 화 하 는 것 이다.
여기 서 먼저 한 가지 지식 포 인 트 를 말씀 드 리 겠 습 니 다.바로 StopWatch 의 사용 입 니 다.최근 에 어떤 사람들 은 StopWatch 를 찾 을 수 없다 고 하 는데,StopWatch 가 도대체 무엇 인지 오늘 설명해 드 리 겠 습 니 다.
StopWatch 는 System.Diagnostics 에서 컨트롤 이름 을 지 었 습 니 다.사용 하려 면 이 네 임 스페이스 를 먼저 참조 해 야 합 니 다.
그 사용 방법 은 다음 과 같다.

var stopWatch = new StopWatch();   //    Stopwatch  

stopWatch.Start();   //    

stopWatch.Stop();   //    

stopWatch.Reset();  //  StopWatch

stopWatch.Restart(); //        StopWatch

stopWatch.ElapsedMilliseconds //  stopWatch          ,     
이번에 사용 한 것 은 이렇게 많은 지식 입 니 다.StopWatch 에 관 한 것 을 더 알 고 싶 습 니 다.바 이 두 에 가 보 세 요.인터넷 에 자료 가 많 습 니 다.
다음은 전체 에 들 어가 서 Parallel.Invoke 방법 을 소개 합 니 다.쓸데없는 말 은 하지 않 겠 습 니 다.먼저 콘 솔 프로그램 을 새로 만 들 고 클래스 를 추가 합 니 다.코드 는 다음 과 같 습 니 다.

public class ParallelDemo
 {
 private Stopwatch stopWatch = new Stopwatch();

 public void Run1()
 {
 Thread.Sleep(2000);
 Console.WriteLine("Task 1 is cost 2 sec");
 }
 public void Run2()
 {
 Thread.Sleep(3000);
 Console.WriteLine("Task 2 is cost 3 sec");
 }

 public void ParallelInvokeMethod()
 {
 stopWatch.Start();
 Parallel.Invoke(Run1, Run2);
 stopWatch.Stop();
 Console.WriteLine("Parallel run " + stopWatch.ElapsedMilliseconds + " ms.");
 
 stopWatch.Restart();
 Run1();
 Run2();
 stopWatch.Stop();
 Console.WriteLine("Normal run " + stopWatch.ElapsedMilliseconds + " ms.");
 }
}
코드 는 매우 간단 합 니 다.먼저 클래스 에 두 가지 방법 을 썼 습 니 다.Run 1 과 Run 2 는 각각 일정한 시간 을 기다 리 고 정 보 를 출력 한 다음 에 테스트 방법 인 ParallelInvokeMethod 를 썼 습 니 다.각각 두 가지 방법 으로 Run 1 과 Run 2 를 호출 한 다음 에 main 방법 에서 사용 합 니 다.다음은 운행 시간 이 어떤 지 살 펴 보 겠 습 니 다.

정상 적 인 호출 은 5 초 이상 걸 렸 을 것 이 고,Parallel.Invoke 방법 호출 은 3 초 밖 에 걸 리 지 않 았 다 는 것 을 짐작 할 수 있 을 것 이다.즉,가장 오래 걸 린 그 방법 은 병행 으로 실행 되 었 고,집행 효율 이 많이 향상 되 었 음 을 알 수 있다.
2、Parallel.For
이 방법 은 For 순환 기능 과 비슷 하 므 로 클래스 에 방법 을 추가 하여 테스트 해 보 겠 습 니 다.코드 는 다음 과 같 습 니 다:

public void ParallelForMethod()
 {
 stopWatch.Start();
 for (int i = 0; i < 10000; i++)
 {
 for (int j = 0; j < 60000; j++)
 {
  int sum = 0;
  sum += i;
 }
 }
 stopWatch.Stop();
 Console.WriteLine("NormalFor run " + stopWatch.ElapsedMilliseconds + " ms.");

 stopWatch.Reset();
 stopWatch.Start();
 Parallel.For(0, 10000, item =>
 {
 for (int j = 0; j < 60000; j++)
 {
  int sum = 0;
  sum += item;
 }
 });
 stopWatch.Stop();
 Console.WriteLine("ParallelFor run " + stopWatch.ElapsedMilliseconds + " ms.");
 
 }
두 개의 순환 을 쓰 고 의미 없 는 일 을 했 습 니 다.그 목적 은 주로 CPU 시간 을 소모 하기 위해 main 방법 에서 호출 되 었 습 니 다.실행 결 과 는 다음 그림 과 같 습 니 다.

이 를 통 해 알 수 있 듯 이 Parallel.For 가 사용 하 는 시간 이 단순 for 보다 1 초 이상 빨 라 졌 다 는 것 을 알 수 있 듯 이 향 상 된 성능 은 매우 가관이다.그렇다면 Parallel.For 는 언제나 for 보다 빠 르 지 않 을까요?답 은 당연히"아니오"입 니 다.그렇지 않 으 면 마이크로소프트 는 아직도 남아 서 무엇 을 합 니까?
다음은 코드 를 수정 하고 전역 변수 num 을 추가 합 니 다.코드 는 다음 과 같 습 니 다.

public void ParallelForMethod()
 {
 var obj = new Object();
 long num = 0;
 ConcurrentBag<long> bag = new ConcurrentBag<long>();

 stopWatch.Start();
 for (int i = 0; i < 10000; i++)
 {
 for (int j = 0; j < 60000; j++)
 {
  //int sum = 0;
  //sum += item;
  num++;
 }
 }
 stopWatch.Stop();
 Console.WriteLine("NormalFor run " + stopWatch.ElapsedMilliseconds + " ms.");

 stopWatch.Reset();
 stopWatch.Start();
 Parallel.For(0, 10000, item =>
 {
 for (int j = 0; j < 60000; j++)
 {
  //int sum = 0;
  //sum += item;
  lock (obj)
  {
  num++;
  }
 }
 });
 stopWatch.Stop();
 Console.WriteLine("ParallelFor run " + stopWatch.ElapsedMilliseconds + " ms.");
 
 }
Parallel.For 는 병렬 로 실행 되 기 때문에 전역 변수 num 에 동시에 접근 합 니 다.정확 한 결 과 를 얻 기 위해 lock 을 사용 해 야 합 니 다.이 때 실행 결 과 를 보십시오.

깜짝 놀 라 셨 죠?Parallel.For 는 15 초 넘 게 걸 렸 고 for 는 이전 과 차이 가 많 지 않 습 니 다.이것 은 전역 변 수 를 병행 하고 방문 하면 자원 쟁탈 이 발생 하기 때문에 대부분의 시간 이 자원 대기 에 소모 된다.
계속 병행 이 라 고 하면 Parallel.For 가 병행 으로 실행 되 는 것 을 어디서 알 수 있 습 니까?다음은 테스트 코드 를 쓰 겠 습 니 다.

Parallel.For(0, 100, i =>
 {
 Console.Write(i + "\t");
 });
0 출력 에서 99 까지 실행 하면 출력 순서 가 잘못 되 었 음 을 발견 할 수 있 습 니 다.for 순 서 를 사용 하 는 것 이 옳 을 것 입 니 다.동시에 실행 하기 때문에 출력 순서 가 다른 상황 이 발생 할 수 있 습 니 다.
3、Parallel.Foreach
이 방법 은 Foreach 방법 과 매우 비슷 합 니 다.구체 적 으로 알 고 싶 은 것 은 바 이 두 에서 자 료 를 좀 볼 수 있 습 니 다.여 기 는 더 이상 말 하지 않 겠 습 니 다.다음은 그 사용 방법 을 제시 하 겠 습 니 다.

List<int> list = new List<int>();
 list.Add(0);
 Parallel.ForEach(list, item =>
 {
 DoWork(item);
 });
2.Parallel 중간 종료 순환 과 이상 처리
1.우리 가 Parallel 을 사용 할 때 반드시 비교적 오래 걸 리 는 작업 을 처리 해 야 합 니 다.물론 CPU 와 메모리 도 많이 소모 합 니 다.만약 에 우리 가 중간 에 멈 추 면 어떻게 합 니까?
직렬 코드 에서 우 리 는 break 하면 됩 니 다.그러나 병행 은 이렇게 간단 하지 않 습 니 다.하지만 괜 찮 습 니 다.병렬 순환 의 의뢰 매개 변수 에서 ParallelLoop State 를 제공 합 니 다.
이 인 스 턴 스 는 Break 와 Stop 방법 을 제공 하여 우리 가 실현 하 는 것 을 도 왔 다.
Break:물론 이것 은 병행 계산 이 가능 한 한 빨리 순환 을 종료 하 는 것 을 알 리 는 것 입 니 다.예 를 들 어 병행 계산 이 100 을 교체 하고 있 으 면 break 후 프로그램 은 100 보다 작은 모든 것 을 교체 할 것 입 니 다.
Stop:이 건 달라 요.예 를 들 어 교체 100 에서 갑자기 stop 을 만나면 아무것도 상관 하지 않 고 바로 물 러 납 니 다.
다음은 코드 테스트 를 작성 해 보 겠 습 니 다.

public void ParallelBreak()
 {
 ConcurrentBag<int> bag = new ConcurrentBag<int>();
 stopWatch.Start();
 Parallel.For(0, 1000, (i, state) =>
 {
 if (bag.Count == 300)
 {
  state.Stop();
  return;
 }
 bag.Add(i);
 });
 stopWatch.Stop();
 Console.WriteLine("Bag count is " + bag.Count + ", " + stopWatch.ElapsedMilliseconds);
 }
여기 서 사용 하 는 것 은 Stop 입 니 다.수량 이 300 개 에 이 르 면 바로 멈 춥 니 다.결 과 를 볼 수 있 는'Bag count is 300'.break 를 사용 하면 300 개 이상 또는 300 개가 나 올 수 있 으 니 테스트 해 보 세 요.
2.이상 처리
우선 임 무 는 병행 계산 입 니 다.처리 과정 에서 n 이상 이 발생 할 수 있 습 니 다.그러면 어떻게 이런 이상 을 얻 을 수 있 습 니까?일반적인 Exception 에 서 는 이상 을 얻 을 수 없 지만,동시에 탄생 하 는 AggregateExcepation 에 서 는 이상 을 얻 을 수 있 습 니 다.
여기에서 우 리 는 Parallel.Invoke 의 코드 를 수정 합 니 다.수정 후 코드 는 다음 과 같 습 니 다.

public class ParallelDemo
 {
 private Stopwatch stopWatch = new Stopwatch();

 public void Run1()
 {
 Thread.Sleep(2000);
 Console.WriteLine("Task 1 is cost 2 sec");
 throw new Exception("Exception in task 1");
 }
 public void Run2()
 {
 Thread.Sleep(3000);
 Console.WriteLine("Task 2 is cost 3 sec");
 throw new Exception("Exception in task 2");
 }

 public void ParallelInvokeMethod()
 {
 stopWatch.Start();
 try
 {
 Parallel.Invoke(Run1, Run2);
 }
 catch (AggregateException aex)
 {
 foreach (var ex in aex.InnerExceptions)
 {
  Console.WriteLine(ex.Message);
 }
 }
 stopWatch.Stop();
 Console.WriteLine("Parallel run " + stopWatch.ElapsedMilliseconds + " ms.");

 stopWatch.Reset();
 stopWatch.Start();
 try
 {
 Run1();
 Run2();
 }
 catch(Exception ex)
 {
 Console.WriteLine(ex.Message);
 }
 stopWatch.Stop();
 Console.WriteLine("Normal run " + stopWatch.ElapsedMilliseconds + " ms.");
 }
}
순서 호출 방법 은 이상 처 리 를 함께 썼 습 니 다.이렇게 하면 Run 1 의 이상 정 보 를 포착 할 수 있 고 여러분 은 따로 쓸 수 있 습 니 다.AggregateException 캡 처 이상 후,foreach 순환 으로 이상 정 보 를 출력 하면 두 개의 이상 정 보 를 모두 표시 할 수 있 습 니 다.
여 기 를 클릭 하여 원본 코드 를 다운로드 하 십시오.
이상 은 c\#병렬 및 다 중 스 레 드 프로 그래 밍-Parallel 의 상세 한 내용 을 알 고 있 습 니 다.c\#병렬 및 다 중 스 레 드 프로 그래 밍 에 관 한 자 료 는 다른 관련 글 을 주목 하 십시오!

좋은 웹페이지 즐겨찾기