오늘은 C#에 있는 병렬처리 Parallel 클래스에 대해서 알아보고자 합니다.
현재 제가 하고 있는 프로젝트 중 그룹으로 묶인 도형을 Binary 처리된 이미지에 맞게
Resize, Move, Rotate하는 메서드를 구현해야하는 작업이 생겼고,
해당 메서드를 단순 for문을 사용해 구현했는데
당연하게도 메서드가 돌아가는 동안에는 Main UI 에 Lock이 걸려서 프로그램이 멈추는 현상이 나왔습니다.
그래서 이걸 비동기 매서드로 만들어서 Main UI에 Lock이 걸리지 않도록 할지
혹은 여러개의 쓰레드를 만들어서 멀티쓰레드를 사용할지 고민이 되었습니다.
비동기 매서드로 만들자니 물론 기존메서드 실행시간보다는 단축되겠지만 순차적으로 처리해야하기 때문에
확실하게 단축되지는 않을 것이라고 판단되엇고,
비동기 매서드를 사용하면 주관적인 느낌일지 모르겠지만 실행이 되는동안에 Main UI를 사용할 수 있으니
실행이 되고있는건지 아닌건지 다른 UI를 사용해줘야지만 알 수 있기 때문에 끌리지는 않았습니다.
그래서 for문을 병렬처리 할 수 있는 방법을 찾아보던 중 Parallel Framework ( PFX ) 에 대해서 알게 되었습니다.
Parallel 클래스란?
Parallel 클래스는 프로세스를 분할하고, CPU의 모든 코어를 활용하여 작업을 병렬로 처리하는 클래스입니다
또한 Parallel.For() 와 Parallel.ForEach() , Parallel.Invoke로 나누어지게 됩니다.
간단하게 설명하자면 기본적으로 for문을 사용할때에는
위와 같은 방식을 사용하게 되는데
이를 콘솔에 띄우게되면
Hellow World1, Hellow World2, Hellow World3, Hellow World4 ...
이렇게 동기처리가되어 순차적으로 출력되게 됩니다.
하지만 Parallel 클래스는 비동기적으로 업무(Task)를 처리해야하기 때문에
처리해야할 업무를 각각 다른 쓰레드에 분리한 뒤 따로 배정하여 진행시키기 때문에
Hellow World1, Hellow World15, Hellow World1000, Hellow World8 ...
이렇게 순서가 없이 먼저 처리되는 업무들이 출력되게 됩니다.
물론 이렇게 간단한 for문 구조는 병렬처리가 아닌 일반 기본구조를 사용하는게
더 효율적이지만 만약 더 복잡한 구조를 사용하게 된다면
Parallel 클래스를 사용하여 병렬처리를 하는게 효과적일 것 입니다.
사실 여기까지는 누구나 이해할 수 있을만한 아주 쉬운 내용입니다.
그런데 저는 과연 이 클래스를 사용하게되면 코어를 모두 사용하는지, 쓰레드는 어떻게 사용하는지
그 방식은 어떻게 되는지가 궁금했습니다.
또한 비동기 작업을 위한 Task와는 어떤 차이점이 있는지도 궁금했습니다.
Task 키워드와의 차이점
Task는 여러 종류의 작업을 처리할 때 사용하는 클래스이고
예를들어
Task.Run() => 설거지하기
Task.Run() => 빨래하기
Task.Run() => 청소하기
Parallel은 같은 작업을 대량으로 반복해야 할 때 주로 사용하는 클래스라고 합니다.
예를들어
var 우편물목록 = new List<편지>();
Parallel.ForEach(우편물목록, 편지 => { 배달하기(편지); });
와 같이 사용하는 것이죠.
그런데 궁금한게 생겼습니다.
결국 C# 내부에서 스레드 풀을 사용해서
필요한 만큼의 스레드를 생성하고, 작업을 스레드에 분배하고, 작업이 끝난 스레드를 재사용하고,
시스템 리소스를 관리 하는것은 같은데
왜 2개의 클래스를 나눠서 하는걸까요??
그래서 생각해보니 병렬처리 클래스를 만든 사람 입장에서 단순하게 생각하면
" 병렬처리를 해야하는 상황은 2가지밖에 없을것이다.
첫번째로는 다양한 업무를 여러 부서에 나눠주고 한번에 마무리하는 것.
두번째로는 한가지의 업무를 한부서의 여러명에게 나눠주고 한번에 마무리하는 것.
내부적으로는 똑같이 스레드 풀을 사용하지만, 두 가지 상황의 코드 사용법이 너무 다르니
하나의 클래스를 사용하면 오히려 복잡해질 수 있다. 클래스를 분리하자!.."
라고 생각하고 만들지 않았을까 합니다.
결론
결론적으로 정리를하면 Parallel과 Task는 내부적으로 같은 스레드 풀을 사용하지만,
서로 다른 병렬 처리 시나리오에 최적화되어 있으니 상황에 맞게 사용해야할 것이고.
제가 처음에 고민했던 도형 그룹의 Resize, Move, Rotate 작업의 경우는 '같은 작업을 여러 도형에 적용'하는 것이므로 Parallel 클래스를 사용하는 것이 적합했습니다.
또한 실제로 Parallel을 적용해본 결과, Main UI의 Lock 현상도 해결되었고 전체 처리 시간도 크게 단축되었습니다.
이처럼 병렬 처리가 필요한 상황에서는:
- 여러 다른 종류의 작업을 동시에 처리해야 한다면 → Task
- 같은 작업을 대량의 데이터에 처리해야 한다면 → Parallel
이 간단한 기준으로 선택하면 될 것이라 판단됩니다 :)
'Program > C#' 카테고리의 다른 글
C# 병렬처리3 _ Mutex (0) | 2024.11.23 |
---|---|
C# 병렬처리2 _ Monitor (0) | 2024.11.22 |
C# 병렬처리1 _ lock (0) | 2024.11.20 |
C# Bitmap (1) | 2024.11.18 |
C# 얕은복사, 깊은복사 (1) | 2024.11.14 |