Featured image of post 스레드와 동시성 (Thread and Concurrency)

스레드와 동시성 (Thread and Concurrency)

스레드를 사용하는 이유에서부터 concurrency와 parallelism의 차이, 그리고 암달의 법칙까지

스레드란

스레드(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) 은 각 코어가 서로 다른 작업을 병렬로 수행한다. 예를 들어, 하나의 데이터 세트에 대해 한 코어는 평균을 계산하고, 다른 코어는 표준편차를 계산하는 방식이다.