스레드란
스레드(Thread)는 CPU가 작업을 수행하는 가장 기본적인 단위이다. 하나의 스레드는 스레드 ID, 프로그램 카운터(PC), 레지스터, 스택으로 구성된다. 여러 개의 스레드는 하나의 프로세스 안에서 생성되어 동작할 수 있는데, 이들은 같은 프로세스에 속해 있기 때문에 코드와 데이터, 파일 및 자원 등을 공유한다.
스레드를 사용하는 이유
현대의 대부분의 응용 프로그램은 다중 스레드로 설계된다. 예를 들어 웹 브라우저는 하나의 스레드가 웹페이지의 이미지를 로드하는 동안, 또 다른 스레드는 사용자의 입력을 기다릴 수 있다.
스레드를 사용하면 다음과 같은 이점이 있다.
응답성(responsiveness): 프로그램이 특정 작업으로 인해 멈추지 않고 사용자와 지속적으로 상호작용할 수 있게 해준다. 예를 들어, 워드 프로세서에서 맞춤법 검사를 별도의 스레드로 실행하면 사용자는 검사가 진행되는 동안에도 작업을 계속할 수 있다.
자원 공유(resource sharing): 스레드는 프로세스 내의 데이터를 자연스럽게 공유할 수 있어, 메모리 사용이 효율적이고 프로그램 구조가 간단해진다.
경제성(economy): 새로운 프로세스를 생성하는 것보다 스레드를 생성하는 것이 훨씬 경제적이다. 스레드는 이미 존재하는 프로세스의 자원을 사용하므로 메모리와 처리 시간 측면에서 비용이 적게 든다.
확장성(scalability): 멀티 코어 시스템에서는 각 코어가 서로 다른 스레드를 동시에 실행할 수 있다. 따라서 스레드를 활용하면 시스템의 성능을 효과적으로 확장할 수 있다.
멀티 코어 프로그래밍
과거에는 프로세서의 성능 향상이 단일 코어의 성능을 높이는 방식으로 이루어졌지만, 최근에는 한 프로세서에 여러 개의 코어를 장착하는 멀티 코어 방식이 일반화되었다. 멀티 코어 시스템은 동시에 여러 작업을 병렬로 수행하여 전체적인 성능을 높일 수 있게 해준다.
이러한 멀티 코어 환경에서 성능을 최대화하려면 프로그램이 여러 스레드를 통해 작업을 병렬적으로 처리할 수 있도록 설계되어야 한다. 그러나 단순히 스레드를 많이 만든다고 해서 성능이 반드시 좋아지는 것은 아니다.
암달의 법칙
암달의 법칙(Amdahl’s Law)은 병렬 처리를 통해 얻을 수 있는 성능 향상을 나타내는 법칙이다. 이 법칙은 전체 작업 중에서 병렬 처리가 가능한 부분과 반드시 순차적으로 처리해야 하는 부분을 나누고, 여러 개의 코어를 추가할 때의 성능 향상을 예측한다.
암달의 법칙은 다음과 같은 식으로 표현된다.
$$\text{speedup} \leq \frac{1}{S + \frac{(1 - S)}{N}}$$
- $S$ : 순차적으로만 처리 가능한 작업 비율
- $N$ : 프로세서 코어 수
이 법칙에 따르면 $N$이 무한대에 가까워지면 속도는 $\frac{1}{S}$에 수렴한다는 것이다. 순차 작업의 비율이 존재하는 한, 아무리 많은 코어를 추가해도 성능 향상에는 명확한 한계가 있다.
병행성과 병렬성
병행성과 병렬성은 비슷하지만 서로 다른 개념이다.
병행성 (concurrency) 은 여러 작업이 시간상으로 겹쳐 진행되는 것을 말한다. 하지만 반드시 동시에 수행되는 것은 아니다. 예를 들어, 단일 코어 프로세서에서도 여러 작업을 병행할 수 있는데, CPU가 빠르게 여러 작업을 번갈아 처리하면서 병행성의 효과를 낸다.
아래 그림에서는 단일 코어 시스템에서 여러 작업(T₁, T₂, T₃, T₄)이 번갈아 수행되는 병행 실행을 나타낸다.
병렬성 (parallelism) 은 여러 작업이 실제로 동시에 수행되는 것이다. 병렬성을 실현하려면 멀티 코어 시스템과 같은 여러 처리기가 필요하다. 즉, 각 작업이 각기 다른 코어에서 동시에 처리되는 방식이다.
아래 그림에서는 멀티 코어 시스템에서 두 개의 코어가 각기 다른 작업을 동시에 수행하는 병렬 실행을 나타낸다.
병렬 실행의 유형
병렬 실행은 데이터와 테스크 두 가지 유형으로 나눌 수 있다.
데이터 병렬 실행(data parallelism) 은 하나의 데이터를 나누어 각 코어가 동일한 작업을 병렬로 수행한다. 예를 들어 큰 배열의 합을 구할 때, 배열을 여러 조각으로 나누어 각각의 코어가 동시에 합을 계산한다.
테스크 병렬 실행(task parallelism) 은 각 코어가 서로 다른 작업을 병렬로 수행한다. 예를 들어, 하나의 데이터 세트에 대해 한 코어는 평균을 계산하고, 다른 코어는 표준편차를 계산하는 방식이다.