프로세스와 스레드 / 멀티 프로세싱과 스레딩의 이해와 활용 예시
Table of Contents
- 01. 선행되어야 할 학습
- 01. 프로세스(Process)와 스레드(Thread)의 기초 개념
- 02. 스레드의 역사
- 03. 스레드를 이해해야 하는 이유 – PID 고갈
- 04. 스레드의 구성 요소 (Multithread)
- 05. 멀티프로세스와 멀티스레드
- 07. 실제 활용 사례 – 웹 브라우저와 서버 응용 프로그램
01. 선행되어야 할 학습
이 교육 자료는 먼저 프로세스의 모든 것 (상태 전이도, PCB, 문맥 교환, 프로세스 구조) 과정을 학습하고 난 이후에 읽기를 권장한다.
01. 프로세스(Process)와 스레드(Thread)의 기초 개념
스레드(Thread)라는 것은 프로세스의 실행 단위(또는 실행 흐름)를 의미한다.
먼저 프로세스와 스레드의 정의를 설명한다.
- 프로세스는 독립적인 실행 단위로, 고유의 메모리 공간을 가진다.
- 스레드는 동일한 프로세스 내에서 실행되며, 메모리 공간을 공유한다.
선행된 학습 과정에서 프로세스는 한 번에 하나의 작업을 처리한다는 개념으로 배웠다. 하지만 이는 전통적인 관점에서만 해당되며, 과거에는 하나의 프로세스가 한 번에 하나의 일만 처리했다. 즉, 전통적인 프로세스는 ‘단일 스레드 프로세스‘라고 표현할 수 있다.
스레드의 도입과 기술 발전으로 인해 프로세스는 동시에 여러 작업을 처리할 수 있게 되었다.
아래 이미지는 ‘단일 스레드 프로세스’와 현재의 ‘멀티 스레드 프로세스’의 기본적인 개념을 표현한다.
- 단일 스레드 프로세스는 파일 다운로드를 순차적으로 하나씩 실행
- 멀티 스레드 프로세스는 동시에 여러 개의 파일 다운로드를 병렬로 실행
02. 스레드의 역사
스레드라는 개념은 1960년대부터 스레드 개념이 존재하였으며, 윈도우 NT 4.0에서 기능이 강화되면서 스레드 기능이 본격적으로 도입되었다. 이후 MS사의 윈도우 XP, 7, 10 등 개인용 PC에서도 쉽게 접할 수 있는 기술이 되면서 스레드의 개념이 보편화되었다.
때문에 현재는 대부분의 운영체제에서 스레드 기능을 지원하며, 이는 개발자가 멀티태스킹을 구현하는데 필수적인 개념이 되었다.
03. 스레드를 이해해야 하는 이유 – PID 고갈
운영자 입장에서 리눅스가 제공하는 최대 프로세스 개수 제한은 단순히 프로세스만 카운팅하는 것이 아니라 스레드까지 포함하여 최대 개수를 계산한다. 따라서 스레드의 수가 많아지면 프로세스 생성 제한에 걸리게 된다.
이는 애플리케이션의 버그로 인해 불필요한 프로세스가 계속해서 생성될 경우 PID 고갈을 유발할 수 있으므로, 스레드를 이해하는 것이 중요하다.
04. 스레드의 구성 요소 (Multithread)
스레드를 단순히 실행 단위로만 이해할 수 있지만, 각 스레드는 서로 다른 구성 요소를 가진다. 이 때문에 스레드마다 각자 다른 코드를 실행할 수 있다.
각 스레드는 다음과 같은 요소를 가집니다:
- 스레드 ID
- PC (프로그램 카운터)
- 레지스터 값
- Stack 영역
프로세스 내에서 공통으로 사용하는 공유 자원:
- Heap 영역
- 데이터 영역
- 코드 영역 (Text 영역)
프로세스의 자원을 공유하는 것이 스레드의 핵심적인 개념이다.
자 그럼 아래 두 그림을 보고 이해하자.
첫 번째 이미지에서는 앞서 배운 메모리 영역에서 스레드가 Stack 영역에 위치해 있다는 것을 알 수 있다.
두 번째 이미지에서는 Code, Data, Files가 공유 자원으로 사용되고, 각 스레드마다 스레드 ID, 레지스터 값, PC, Stack을 다르게 가져가는 것을 알 수 있다.
최근 많은 운영체제가 CPU 처리할 작업을 전달할 때 프로세스가 아닌 스레드 단위로 전달한다.
이는 스레드가 프로세스보다 자원이 적게 필요하기 때문에 스레드 단위로 처리하면 CPU 자원을 효율적으로 사용할 수 있기 때문이다. 또한, 스레드 단위가 프로세스보다 빠르게 생성되고 종료될 수 있기 때문에 효율성이 더 높다.
05. 멀티프로세스와 멀티스레드
- 멀티프로세스(Multiprocess) : 여러 프로세스를 동시에 실행하는 것. (예: fork()를 이용하여 새로운 프로세스를 생성함.)
- 멀티스레드(Multithread) :하나의 프로세스 내에서 여러 스레드를 동시에 실행하는 방법.
멀티 프로세싱과 멀티 스레딩의 차이와 장단점
멀티프로세스는 프로세스 간 자원을 공유하지 않지만, 멀티스레드는 같은 프로세스 내의 자원을 공유한다.
멀티프로세스는 fork를 이용하여 프로세스를 생성하며, 코드, 데이터, 힙 영역이 복제되어 메모리에 적재된다. 즉, 멀티프로세스로 수행하면 PID와 메모리 주소를 제외한 모든 것이 동일한 두 개의 프로세스가 메모리에 적재된다. 이로 인해 동일한 내용이 중복 적재되어 메모리 낭비가 발생할 수 있다.
반면, 스레드는 공유 자원을 사용하므로 메모리를 더 효율적으로 사용할 수 있으며, 같은 프로세스 내에서 통신에 유리하다.
멀티프로세스 환경에서는 하나의 프로세스에 문제가 생겨도 다른 프로세스에 영향이 적거나 없다. 하지만 멀티스레드 환경에서는 프로세스 자원을 공유하기 때문에, 하나의 스레드에 문제가 생기면 전체 프로세스에 영향을 미칠 수 있다.
IPC (Inter-Process Communication) / 프로세스 간 통신
프로세스끼리는 기본적으로 자원을 공유하지 않는다. 하지만 IPC를 이용하면 프로세스 간 자원을 공유하고 데이터를 주고받을 수 있다.
통신이란 단어가 네트워크 통신에서 많이 쓰이지만, 같은 컴퓨터 내의 서로 다른 프로세스나 스레드끼리 데이터를 주고받는 것도 통신이라 한다.
예를 들어, hello.txt 파일을 프로세스 A가 쓰고, 프로세스 B가 읽는다면 이는 '파일을 통한 프로세스 간 통신'이 된다.
또한, 프로세스들은 공유 메모리(Shared memory)를 사용하여 메모리 내에서 데이터를 주고받을 수 있다. 예를 들어, 프로세스 A와 B가 공유하는 메모리 영역에 있는 'name'이라는 전역 변수를 통해 값을 주고받을 수 있다.
이 외에도 프로세스들은 소켓, 파이프 등을 통해 통신할 수 있다. 프로세스 간의 데이터 통신은 스레드 간 통신보다 다소 복잡할 수 있다.
IPC 개념을 사용하여 프로세스 간 통신하는 방법 예시
- 파일을 이용한 통신
- 공유 메모리를 이용한 데이터 통신
- 소켓을 이용한 통신
- 파이프를 이용한 통신
과거에는 새로운 CPU가 출시될 때마다 논리 CPU 당 성능이 극적으로 향상되었다. 그러나 발열 문제 등으로 인해 CPU 당 성능을 향상시키는 것이 점점 어려워졌다.
이로 인해 CPU 세대가 바뀌어도 CPU 당 성능은 개선 정도에 그치고 있으며, 대신 CPU 코어 수를 늘리는 방법으로 성능을 향상시키고 있다.
커널 또한 이러한 시대 흐름에 맞춰 코어 수가 증가에 대응하도록 소프트웨어를 변화시켰다. 예를 들어, 과거 init 프로세스(PID 1)는 한 번에 하나의 프로세스만 실행시켰지만, systemd로 변경되면서 동시에 여러 프로세스를 실행시킬 수 있게 되었다.
07. 실제 활용 사례 – 웹 브라우저와 서버 응용 프로그램
웹 브라우저
멀티프로세스 아키텍처 – 크롬 브라우저
각 탭을 별도의 프로세스로 실행해, 한 탭의 오류가 전체 브라우저에 영향을 미치지 않도록 한다. 플러그인과 확장 프로그램도 독립적인 프로세스로 실행되어 안정성을 높인다.
- 내부 스레드 사용 : 각 탭 내에서는 렌더링, 네트워크 처리, 사용자 인터페이스 작업을 별도의 스레드로 처리하여 성능을 최적화한다.
- 크롬 브라우저가 작업 관리자에서 여러 개의 프로세스로 보이는 이유는 각 탭, 플러그인, 확장 프로그램이 독립적인 프로세스로 실행되기 때문이다, 따라서 크롬 브라우저는 프로세스와 스레드 둘 다 사용하여 효율적으로 동작하게 만들어졌다.
장점
- 안정성 : 한 탭이 충돌해도 다른 탭에 영향을 미치지 않는다.
- 성능 : 여러 스레드를 활용해 작업을 병렬로 처리함으로써 속도 향상을 도모한다.
서버 응용 프로그램
- 멀티프로세싱
- 웹 서버 : 아파치 웹 서버는 각 클라이언트 요청을 독립적인 프로세스로 처리한다. 이는 클라이언트 간의 격리와 독립성을 보장한다.
- 데이터베이스 서버: MySQL과 같은 데이터베이스 서버도 멀티프로세싱을 활용해 다수의 클라이언트 요청을 병렬로 처리한다.
- 멀티스레딩
- 애플리케이션 서버: 자바 기반의 애플리케이션 서버(Tomcat 등)는 각 클라이언트 요청을 별도의 스레드로 처리하여 응답 시간을 단축하고, 동시에 여러 요청을 처리할 수 있도록한다.
- 비동기 서버: Node.js는 비동기 이벤트 기반 아키텍처를 통해 높은 동시성을 제공하며, 하나의 스레드에서 다수의 클라이언트 요청을 효율적으로 처리한다.
- 장점:
- 확장성: 많은 요청을 병렬로 처리할 수 있어 서버의 확장성이 향상된다.
- 성능: 멀티스레딩을 통해 빠른 응답 속도를 제공하고, CPU 자원을 효율적으로 사용한다.
최신 스레드 관리 기술
- 비동기 프로그래밍: Node.js, Python의 asyncio 등 비동기 프로그래밍 모델을 통해 효율적인 I/O 처리와 높은 동시성을 제공한다.
- 멀티코어 활용: 최신 CPU의 다중 코어를 활용하기 위해, 언어 및 런타임 환경에서 멀티스레딩과 멀티프로세싱을 지원원한다.
- 병렬 처리 라이브러리: OpenMP, Intel TBB 등은 멀티스레딩을 쉽게 구현할 수 있는 도구와 라이브러리를 제공한다.
컨테이너화 기술 (Docker)
컨테이너화 기술은 실제 프로세스와 스레드와는 다르다. 그러나 개념적으로 비슷한 개념이 있기에 최신 트렌드 및 기술에 포함하였다
- 격리된 환경 : 각 컨테이너는 독립적인 프로세스로 실행되어 애플리케이션의 격리와 안정성을 높인다.
- 리소스 관리 : 컨테이너는 여러 스레드를 사용하여 성능 최적화와 자원 활용을 극대화한다.
- 오케스트레이션 : Kubernetes와 같은 도구는 여러 컨테이너를 관리하고, 스케일링 및 배포를 자동화한다.