다중 스레드 아키텍처 (Multi-threaded Architecture)
1. 개요
다중 스레드 아키텍처란 하나의 프로세스 내에서 실행 흐름의 단위인 스레드(Thread)를 여러 개 생성하여 동시에 작업을 수행하도록 설계된 소프트웨어 구조를 의미한다.
프로세스(Process)가 운영체제로부터 자원을 할당받는 실행 중인 프로그램의 독립적인 인스턴스라면, 스레드(Thread)는 프로세스 내에서 실행되는 더 작은 실행 단위이다. 현대 컴퓨팅 환경에서 다중 스레딩이 필수적인 이유는 다음과 같다.
- 응답성 향상: GUI 애플리케이션에서 시간이 오래 걸리는 작업(파일 다운로드 등)을 백그라운드 스레드로 처리함으로써 사용자의 입력에 즉각적으로 반응할 수 있다.
- 자원 효율성: 프로세스를 여러 개 생성하는 것보다 스레드를 생성하는 것이 메모리 소비가 적고 생성/종료 속도가 빠르다.
- 멀티코어 활용: 물리적인 CPU 코어가 여러 개인 환경에서 작업을 병렬로 분산 처리하여 전체적인 실행 시간을 단축할 수 있다.
1.1 동시성(Concurrency)과 병렬성(Parallelism)
다중 스레드 아키텍처를 이해하기 위해서는 동시성과 병렬성의 차이를 구분하는 것이 중요하다.
- 동시성 (Concurrency): 싱글 코어 환경에서 여러 스레드가 아주 빠르게 번갈아 가며 실행되어, 사용자에게는 마치 동시에 실행되는 것처럼 보이는 논리적인 개념이다. 이는 시분할(Time-slicing) 방식을 통해 구현된다.
- 병렬성 (Parallelism): 멀티 코어 환경에서 실제로 여러 스레드가 서로 다른 코어에서 물리적으로 동시에 실행되는 상태를 의미한다.
2. 동작 원리와 메커니즘
다중 스레드 아키텍처의 핵심은 프로세스의 자원을 공유하면서 실행 흐름만 분리하는 것이다.
2.1 메모리 구조와 독립성
스레드들은 프로세스의 코드(Code), 데이터(Data), 힙(Heap) 영역을 공유한다. 하지만 각 스레드는 독립적인 실행 흐름을 유지하기 위해 자신만의 스택(Stack) 영역과 PC(Program Counter) 레지스터를 가진다. 이를 통해 각 스레드는 함수 호출 기록과 현재 실행 위치를 개별적으로 관리할 수 있다.
(그림: 프로세스 내 공유 영역과 스레드별 독립 영역의 구조)
2.2 컨텍스트 스위칭 (Context Switching)
CPU가 한 스레드에서 다른 스레드로 실행 제어권을 넘기는 과정을 컨텍스트 스위칭이라 한다. 이때 현재 스레드의 상태(레지스터 값, 스택 포인터 등)를 저장하고 새로운 스레드의 상태를 복원한다. 프로세스 간의 컨텍스트 스위칭보다 스레드 간의 스위칭이 빠른 이유는 공유 메모리 영역이 많아 캐시 메모리 플러시(Flush) 비용이 적기 때문이다.
2.3 프로세스 vs 스레드 비교
| 구분 |
프로세스 (Process) |
스레드 (Thread) |
| 정의 |
실행 중인 프로그램의 독립적 단위 |
프로세스 내의 실행 흐름 단위 |
| 자원 공유 |
독립된 메모리 공간 (공유 불가) |
프로세스 내 메모리(Heap, Data) 공유 |
| 생성 비용 |
높음 (OS의 무거운 개입) |
낮음 (가벼운 생성 및 전환) |
| 영향도 |
한 프로세스 장애가 타 프로세스에 영향 없음 |
한 스레드 장애가 프로세스 전체에 영향 가능 |
| 통신 방식 |
IPC (Inter-Process Communication) 필요 |
공유 변수를 통한 직접 통신 가능 |
3. 주요 구현 모델
스레드는 관리 주체에 따라 사용자 수준과 커널 수준으로 나뉘며, 이들의 매핑 방식에 따라 성능과 특성이 달라진다.
- 사용자 수준 스레드 (User-level Thread): 사용자 영역의 라이브러리가 스레드를 관리한다. OS 커널은 스레드의 존재를 모르며 하나의 프로세스로 인식한다. 컨텍스트 스위칭이 매우 빠르지만, 하나의 스레드가 블로킹(Blocking)되면 프로세스 전체가 블로킹 상태가 된다.
- 커널 수준 스레드 (Kernel-level Thread): OS 커널이 직접 스레드를 생성하고 스케줄링한다. 하나의 스레드가 블로킹되어도 다른 스레드가 실행될 수 있으며, 멀티프로세서 환경에서 병렬 실행이 가능하다.
3.2 매핑 모델
| 모델 |
설명 |
장점 |
단점 |
| 다대일 (M:1) |
여러 사용자 스레드를 하나의 커널 스레드에 매핑 |
스위칭 오버헤드 매우 낮음 |
병렬 처리 불가, 블로킹 시 전체 블로킹 |
| 일대일 (1:1) |
각 사용자 스레드마다 하나의 커널 스레드 생성 |
진정한 병렬 처리 가능, 블로킹 영향 최소화 |
커널 스레드 생성 비용으로 인한 오버헤드 |
| 다대다 (M:N) |
여러 사용자 스레드를 적절한 수의 커널 스레드에 매핑 |
유연한 자원 활용, 효율적인 병렬 처리 |
구현 복잡도가 매우 높음 |
4. 동기화 및 동시성 제어
여러 스레드가 공유 자원에 동시에 접근할 때 데이터의 일관성이 깨지는 경쟁 상태(Race Condition)가 발생한다. 이를 방지하기 위해 특정 코드 영역을 임계 구역(Critical Section)으로 설정하고 동기화 기법을 적용한다.
4.1 동기화 기법
- 뮤텍스 (Mutex): 상호 배제(Mutual Exclusion)의 약자로, 공유 자원을 점유하기 위한 '열쇠' 개념이다. 한 번에 하나의 스레드만 자원을 사용할 수 있게 하며, 락(Lock)을 획득한 스레드만이 해제할 수 있다.
- 세마포어 (Semaphore): 공유 자원의 개수를 나타내는 카운터를 사용하여, 지정된 개수만큼의 스레드가 동시에 접근할 수 있도록 제어한다.
- 모니터 (Monitor): 뮤텍스와 조건 변수를 결합한 고수준 동기화 도구로, 프로그래밍 언어 차원에서 상호 배제를 보장한다. (예: Java의
synchronized 키워드)
4.2 뮤텍스 구현 예시 (Java)
public class Counter {
private final Lock lock = new ReentrantLock();
private int sharedResource = 0;
public void increment() {
lock.lock(); // 임계 구역 진입 전 락 획득
try {
sharedResource++; // 공유 자원 수정 (Critical Section)
} finally {
lock.unlock(); // 작업 완료 후 락 해제
}
}
}
5. 주요 문제점과 해결 방안
5.1 교착 상태 (Deadlock)
두 개 이상의 스레드가 서로가 가진 자원을 기다리며 무한히 대기하는 상태이다.
* 발생 조건: 상호 배제, 점유 및 대기, 비선점, 환형 대기(Circular Wait)의 4가지 조건이 모두 충족될 때 발생한다.
* 해결 방안:
* 예방: 자원 할당 순서를 정하여 환형 대기를 방지한다.
* 회피: 은행원 알고리즘 등을 사용하여 안전 상태인지 확인 후 자원을 할당한다.
* 탐지 및 복구: 교착 상태를 주기적으로 탐지하고, 문제가 발생한 스레드를 강제 종료하거나 자원을 선점하여 해결한다.
* 타임아웃: 일정 시간 동안 락을 획득하지 못하면 포기하는 방식을 사용한다.
5.2 스레드 안전성 (Thread Safety)
여러 스레드가 동시에 접근해도 프로그램의 정확성이 유지되는 상태를 말한다.
* 불변 객체 (Immutable Object): 객체 생성 후 상태를 변경할 수 없게 만들어 동기화 필요성을 원천적으로 제거한다.
* 원자적 연산 (Atomic Operation): 더 이상 쪼갤 수 없는 최소 단위의 연산을 사용하여 중간 단계에서 다른 스레드가 개입하지 못하게 한다.
6. 추가 아키텍처 요소
6.1 스레드 풀 (Thread Pool)
스레드 풀은 미리 일정 수의 스레드를 생성하여 풀(Pool)에 저장해 두고, 작업이 요청될 때마다 할당하여 사용하는 패턴이다.
* 구조: 작업 큐(Work Queue)에 처리해야 할 작업들이 쌓이면, 대기 중인 워커 스레드(Worker Thread)가 큐에서 작업을 하나씩 꺼내어 처리하고 다시 풀로 복귀하는 구조이다.
* 장점:
* 오버헤드 감소: 스레드의 빈번한 생성과 소멸에 따른 비용을 절감한다.
* 자원 관리: 최대 스레드 수를 제한함으로써 시스템 자원의 고갈을 방지하고 안정성을 높인다.
* 응답 속도 향상: 이미 생성된 스레드를 즉시 사용하므로 작업 처리 시작 시간이 단축된다.
6.2 스레드 로컬 저장소 (Thread Local Storage, TLS)
TLS는 모든 스레드가 공유하는 메모리 영역과 달리, 각 스레드만이 접근할 수 있는 전용 저장 공간을 제공하는 메커니즘이다.
* 목적: 전역 변수를 사용하면서도 스레드 간의 간섭을 피하고 싶을 때 사용한다.
* 활용: 스레드별 고유 ID 저장, 데이터베이스 연결 객체(Connection) 관리, 사용자 세션 정보 유지 등에 활용된다.
6.3 하드웨어 가속 및 멀티코어 활용
- 하이퍼스레딩 (Hyper-Threading): 하나의 물리 코어를 두 개의 논리 코어로 인식시켜, CPU 파이프라인의 유휴 시간을 줄이고 처리량을 높인다.
- SIMD (Single Instruction, Multiple Data): 하나의 명령어로 여러 데이터를 동시에 처리하는 벡터 연산을 통해 데이터 병렬성을 극대화한다.
- NUMA (Non-Uniform Memory Access): 멀티 프로세서 환경에서 각 CPU가 인접한 메모리에 더 빠르게 접근하도록 설계하여 메모리 병목 현상을 줄인다.
7. 활용 사례 및 최적화 전략
7.1 실제 적용 사례
- GUI 애플리케이션: 메인 스레드(UI 스레드)는 화면 렌더링과 사용자 입력만 처리하고, 무거운 연산은 워커 스레드(Worker Thread)에 위임하여 '응답 없음' 상태를 방지한다.
- 웹 서버: 요청마다 스레드를 생성하는 대신, 앞서 설명한 스레드 풀을 통해 요청을 처리함으로써 서버의 처리 효율을 극대화한다.
7.2 최적 스레드 수 산정
무조건 스레드 수를 늘린다고 성능이 향상되지 않으며, 과도한 스레드는 컨텍스트 스위칭 오버헤드를 증가시킨다.
* CPU 집약적 작업: $\text{CPU 코어 수} + 1$ (CPU 코어 수 + 1) 개 정도의 스레드가 적당하다.
* I/O 집약적 작업: $\text{CPU 코어 수} \times (1 + \frac{\text{대기 시간}}{\text{서비스 시간}})$ (CPU 코어 수 * (1 + 대기 시간 / 서비스 시간)) 공식을 통해 대기 시간을 고려한 더 많은 스레드를 배치한다.
7.3 언어별 동시성 모델 비교
| 언어 |
주요 모델 |
특징 |
비고 |
| Java |
OS 스레드 기반 (Platform Thread) |
1:1 매핑, 강력한 동기화 라이브러리 제공 |
최근 Virtual Thread(Project Loom) 도입 |
| Go |
고루틴 (Goroutine) |
M:N 매핑, 매우 가벼운 사용자 수준 스레드 |
채널(Channel)을 통한 메시지 통신 강조 |
| Python |
GIL (Global Interpreter Lock) |
한 번에 하나의 스레드만 바이트코드 실행 가능 |
멀티코어 활용을 위해 multiprocessing 사용 |
| Rust |
소유권 기반 동시성 |
컴파일 타임에 데이터 경합(Data Race) 방지 |
메모리 안전성과 고성능 병렬 처리 동시 달성 |
분류: 기술 / 소프트웨어 아키텍처 / 병렬 처리
# 다중 스레드 아키텍처 (Multi-threaded Architecture)
## 1. 개요
다중 스레드 아키텍처란 하나의 프로세스 내에서 실행 흐름의 단위인 스레드(Thread)를 여러 개 생성하여 동시에 작업을 수행하도록 설계된 소프트웨어 구조를 의미한다.
**프로세스(Process)**가 운영체제로부터 자원을 할당받는 실행 중인 프로그램의 독립적인 인스턴스라면, **스레드(Thread)**는 프로세스 내에서 실행되는 더 작은 실행 단위이다. 현대 컴퓨팅 환경에서 다중 스레딩이 필수적인 이유는 다음과 같다.
* **응답성 향상:** GUI 애플리케이션에서 시간이 오래 걸리는 작업(파일 다운로드 등)을 백그라운드 스레드로 처리함으로써 사용자의 입력에 즉각적으로 반응할 수 있다.
* **자원 효율성:** 프로세스를 여러 개 생성하는 것보다 스레드를 생성하는 것이 메모리 소비가 적고 생성/종료 속도가 빠르다.
* **멀티코어 활용:** 물리적인 CPU 코어가 여러 개인 환경에서 작업을 병렬로 분산 처리하여 전체적인 실행 시간을 단축할 수 있다.
### 1.1 동시성(Concurrency)과 병렬성(Parallelism)
다중 스레드 아키텍처를 이해하기 위해서는 동시성과 병렬성의 차이를 구분하는 것이 중요하다.
* **동시성 (Concurrency):** 싱글 코어 환경에서 여러 스레드가 아주 빠르게 번갈아 가며 실행되어, 사용자에게는 마치 동시에 실행되는 것처럼 보이는 **논리적인 개념**이다. 이는 시분할(Time-slicing) 방식을 통해 구현된다.
* **병렬성 (Parallelism):** 멀티 코어 환경에서 실제로 여러 스레드가 서로 다른 코어에서 **물리적으로 동시에 실행**되는 상태를 의미한다.
## 2. 동작 원리와 메커니즘
다중 스레드 아키텍처의 핵심은 프로세스의 자원을 공유하면서 실행 흐름만 분리하는 것이다.
### 2.1 메모리 구조와 독립성
스레드들은 프로세스의 **코드(Code), 데이터(Data), 힙(Heap)** 영역을 공유한다. 하지만 각 스레드는 독립적인 실행 흐름을 유지하기 위해 자신만의 **스택(Stack)** 영역과 **PC(Program Counter) 레지스터**를 가진다. 이를 통해 각 스레드는 함수 호출 기록과 현재 실행 위치를 개별적으로 관리할 수 있다.
+vs+Private+(Stack,PC))
*(그림: 프로세스 내 공유 영역과 스레드별 독립 영역의 구조)*
### 2.2 컨텍스트 스위칭 (Context Switching)
CPU가 한 스레드에서 다른 스레드로 실행 제어권을 넘기는 과정을 컨텍스트 스위칭이라 한다. 이때 현재 스레드의 상태(레지스터 값, 스택 포인터 등)를 저장하고 새로운 스레드의 상태를 복원한다. 프로세스 간의 컨텍스트 스위칭보다 스레드 간의 스위칭이 빠른 이유는 공유 메모리 영역이 많아 캐시 메모리 플러시(Flush) 비용이 적기 때문이다.
### 2.3 프로세스 vs 스레드 비교
| 구분 | 프로세스 (Process) | 스레드 (Thread) |
| :--- | :--- | :--- |
| **정의** | 실행 중인 프로그램의 독립적 단위 | 프로세스 내의 실행 흐름 단위 |
| **자원 공유** | 독립된 메모리 공간 (공유 불가) | 프로세스 내 메모리(Heap, Data) 공유 |
| **생성 비용** | 높음 (OS의 무거운 개입) | 낮음 (가벼운 생성 및 전환) |
| **영향도** | 한 프로세스 장애가 타 프로세스에 영향 없음 | 한 스레드 장애가 프로세스 전체에 영향 가능 |
| **통신 방식** | IPC (Inter-Process Communication) 필요 | 공유 변수를 통한 직접 통신 가능 |
## 3. 주요 구현 모델
스레드는 관리 주체에 따라 사용자 수준과 커널 수준으로 나뉘며, 이들의 매핑 방식에 따라 성능과 특성이 달라진다.
### 3.1 사용자 수준 스레드 vs 커널 수준 스레드
* **사용자 수준 스레드 (User-level Thread):** 사용자 영역의 라이브러리가 스레드를 관리한다. OS 커널은 스레드의 존재를 모르며 하나의 프로세스로 인식한다. 컨텍스트 스위칭이 매우 빠르지만, 하나의 스레드가 블로킹(Blocking)되면 프로세스 전체가 블로킹 상태가 된다.
* **커널 수준 스레드 (Kernel-level Thread):** OS 커널이 직접 스레드를 생성하고 스케줄링한다. 하나의 스레드가 블로킹되어도 다른 스레드가 실행될 수 있으며, 멀티프로세서 환경에서 병렬 실행이 가능하다.
### 3.2 매핑 모델
| 모델 | 설명 | 장점 | 단점 |
| :--- | :--- | :--- | :--- |
| **다대일 (M:1)** | 여러 사용자 스레드를 하나의 커널 스레드에 매핑 | 스위칭 오버헤드 매우 낮음 | 병렬 처리 불가, 블로킹 시 전체 블로킹 |
| **일대일 (1:1)** | 각 사용자 스레드마다 하나의 커널 스레드 생성 | 진정한 병렬 처리 가능, 블로킹 영향 최소화 | 커널 스레드 생성 비용으로 인한 오버헤드 |
| **다대다 (M:N)** | 여러 사용자 스레드를 적절한 수의 커널 스레드에 매핑 | 유연한 자원 활용, 효율적인 병렬 처리 | 구현 복잡도가 매우 높음 |
## 4. 동기화 및 동시성 제어
여러 스레드가 공유 자원에 동시에 접근할 때 데이터의 일관성이 깨지는 **경쟁 상태(Race Condition)**가 발생한다. 이를 방지하기 위해 특정 코드 영역을 **임계 구역(Critical Section)**으로 설정하고 동기화 기법을 적용한다.
### 4.1 동기화 기법
* **뮤텍스 (Mutex):** 상호 배제(Mutual Exclusion)의 약자로, 공유 자원을 점유하기 위한 '열쇠' 개념이다. 한 번에 하나의 스레드만 자원을 사용할 수 있게 하며, 락(Lock)을 획득한 스레드만이 해제할 수 있다.
* **세마포어 (Semaphore):** 공유 자원의 개수를 나타내는 카운터를 사용하여, 지정된 개수만큼의 스레드가 동시에 접근할 수 있도록 제어한다.
* **모니터 (Monitor):** 뮤텍스와 조건 변수를 결합한 고수준 동기화 도구로, 프로그래밍 언어 차원에서 상호 배제를 보장한다. (예: Java의 `synchronized` 키워드)
### 4.2 뮤텍스 구현 예시 (Java)
```java
public class Counter {
private final Lock lock = new ReentrantLock();
private int sharedResource = 0;
public void increment() {
lock.lock(); // 임계 구역 진입 전 락 획득
try {
sharedResource++; // 공유 자원 수정 (Critical Section)
} finally {
lock.unlock(); // 작업 완료 후 락 해제
}
}
}
```
## 5. 주요 문제점과 해결 방안
### 5.1 교착 상태 (Deadlock)
두 개 이상의 스레드가 서로가 가진 자원을 기다리며 무한히 대기하는 상태이다.
* **발생 조건:** 상호 배제, 점유 및 대기, 비선점, 환형 대기(Circular Wait)의 4가지 조건이 모두 충족될 때 발생한다.
* **해결 방안:**
* **예방:** 자원 할당 순서를 정하여 환형 대기를 방지한다.
* **회피:** 은행원 알고리즘 등을 사용하여 안전 상태인지 확인 후 자원을 할당한다.
* **탐지 및 복구:** 교착 상태를 주기적으로 탐지하고, 문제가 발생한 스레드를 강제 종료하거나 자원을 선점하여 해결한다.
* **타임아웃:** 일정 시간 동안 락을 획득하지 못하면 포기하는 방식을 사용한다.
### 5.2 스레드 안전성 (Thread Safety)
여러 스레드가 동시에 접근해도 프로그램의 정확성이 유지되는 상태를 말한다.
* **불변 객체 (Immutable Object):** 객체 생성 후 상태를 변경할 수 없게 만들어 동기화 필요성을 원천적으로 제거한다.
* **원자적 연산 (Atomic Operation):** 더 이상 쪼갤 수 없는 최소 단위의 연산을 사용하여 중간 단계에서 다른 스레드가 개입하지 못하게 한다.
## 6. 추가 아키텍처 요소
### 6.1 스레드 풀 (Thread Pool)
스레드 풀은 미리 일정 수의 스레드를 생성하여 풀(Pool)에 저장해 두고, 작업이 요청될 때마다 할당하여 사용하는 패턴이다.
* **구조:** **작업 큐(Work Queue)**에 처리해야 할 작업들이 쌓이면, 대기 중인 **워커 스레드(Worker Thread)**가 큐에서 작업을 하나씩 꺼내어 처리하고 다시 풀로 복귀하는 구조이다.
* **장점:**
* **오버헤드 감소:** 스레드의 빈번한 생성과 소멸에 따른 비용을 절감한다.
* **자원 관리:** 최대 스레드 수를 제한함으로써 시스템 자원의 고갈을 방지하고 안정성을 높인다.
* **응답 속도 향상:** 이미 생성된 스레드를 즉시 사용하므로 작업 처리 시작 시간이 단축된다.
### 6.2 스레드 로컬 저장소 (Thread Local Storage, TLS)
TLS는 모든 스레드가 공유하는 메모리 영역과 달리, **각 스레드만이 접근할 수 있는 전용 저장 공간**을 제공하는 메커니즘이다.
* **목적:** 전역 변수를 사용하면서도 스레드 간의 간섭을 피하고 싶을 때 사용한다.
* **활용:** 스레드별 고유 ID 저장, 데이터베이스 연결 객체(Connection) 관리, 사용자 세션 정보 유지 등에 활용된다.
### 6.3 하드웨어 가속 및 멀티코어 활용
* **하이퍼스레딩 (Hyper-Threading):** 하나의 물리 코어를 두 개의 논리 코어로 인식시켜, CPU 파이프라인의 유휴 시간을 줄이고 처리량을 높인다.
* **SIMD (Single Instruction, Multiple Data):** 하나의 명령어로 여러 데이터를 동시에 처리하는 벡터 연산을 통해 데이터 병렬성을 극대화한다.
* **NUMA (Non-Uniform Memory Access):** 멀티 프로세서 환경에서 각 CPU가 인접한 메모리에 더 빠르게 접근하도록 설계하여 메모리 병목 현상을 줄인다.
## 7. 활용 사례 및 최적화 전략
### 7.1 실제 적용 사례
* **GUI 애플리케이션:** 메인 스레드(UI 스레드)는 화면 렌더링과 사용자 입력만 처리하고, 무거운 연산은 워커 스레드(Worker Thread)에 위임하여 '응답 없음' 상태를 방지한다.
* **웹 서버:** 요청마다 스레드를 생성하는 대신, 앞서 설명한 스레드 풀을 통해 요청을 처리함으로써 서버의 처리 효율을 극대화한다.
### 7.2 최적 스레드 수 산정
무조건 스레드 수를 늘린다고 성능이 향상되지 않으며, 과도한 스레드는 컨텍스트 스위칭 오버헤드를 증가시킨다.
* **CPU 집약적 작업:** $\text{CPU 코어 수} + 1$ (CPU 코어 수 + 1) 개 정도의 스레드가 적당하다.
* **I/O 집약적 작업:** $\text{CPU 코어 수} \times (1 + \frac{\text{대기 시간}}{\text{서비스 시간}})$ (CPU 코어 수 * (1 + 대기 시간 / 서비스 시간)) 공식을 통해 대기 시간을 고려한 더 많은 스레드를 배치한다.
### 7.3 언어별 동시성 모델 비교
| 언어 | 주요 모델 | 특징 | 비고 |
| :--- | :--- | :--- | :--- |
| **Java** | OS 스레드 기반 (Platform Thread) | 1:1 매핑, 강력한 동기화 라이브러리 제공 | 최근 Virtual Thread(Project Loom) 도입 |
| **Go** | 고루틴 (Goroutine) | M:N 매핑, 매우 가벼운 사용자 수준 스레드 | 채널(Channel)을 통한 메시지 통신 강조 |
| **Python** | GIL (Global Interpreter Lock) | 한 번에 하나의 스레드만 바이트코드 실행 가능 | 멀티코어 활용을 위해 `multiprocessing` 사용 |
| **Rust** | 소유권 기반 동시성 | 컴파일 타임에 데이터 경합(Data Race) 방지 | 메모리 안전성과 고성능 병렬 처리 동시 달성 |
분류: 기술 / 소프트웨어 아키텍처 / 병렬 처리