멀티스레딩과 멀티프로세싱의 차이
멀티스레딩 (Multi-threading)
➡️하나의 프로세스 내에서 여러 스레드(Thread)를 실행(메모리 공유, 같은 자원에 접근 가능)
특징
- 경량 실행 단위 (스레드 간 메모리 공유)
- I/O 작업에 유리 (ex. 파일 읽기/쓰기, 네트워크 요청 등)
- 파이썬은 GIL(Global Interpreter Lock)의 영향을 받아서 한 시점에 하나의 스레드만 실행됨 → CPU 연산에서는 병렬 처리 효과가 떨어짐.
멀티프로세싱 (Multi-processing)
➡️ 여러 프로세스(Process-> 독립된 메모리 공간)를 생성해서 병렬로 실행
특징
- CPU 연산에 유리 (병렬 계산 가능)
- GIL의 영향을 받지 않음 → 진정한 병렬 처리 가능
- 프로세스 간 통신(IPC)은 비교적 비용이 큼 (Queue, Pipe 등 사용)
✅ 간단 정리
실행 단위 | 스레드(Thread) | 프로세스(Process) |
메모리 공유 | 공유 | 독립적 |
GIL 영향 | O | X |
병렬 처리 | I/O에 적합 | CPU 연산에 적합 |
메모리 사용 | 적음 | 많음 |
속도 | 빠를 수 있음 (I/O) | CPU 코어 수만큼 병렬 처리 가능 |
프로세스(Process)란?
➡️ 운영체제에서 실행중인 프로그램 하나
ex)문서를 여는 순간, 크롬을 켜는 순간 하나의 프로세스가 실행됨
특징
- 하나의 프로세스는 독립된 메모리 공간을 가지고 있다.(다른 프로세스와 메모리 공유X) -> 안정성이 높다.
- " 자원을 독립적으로 관리한다.(각각의 프로세스마다 CPU, 메모리 등이 별도로 할당됨)
- " 따라서 하나의 컴퓨터에서 여러 프로세스가 동시에 실행될 수 있다.(멀티태스킹) -> 병렬처리 가능.
단점
- 각각의 프로세스에 메모리 할당 -> 메모리 사용량이 높다. -> 높은 자원 소비
- 프로세스 간에 데이터를 공유하려면 통신이 복잡하고 느림 -> 성능상 오버헤드 발생할 수 있음.
스레드(Thread)란?
➡️ 프로세스 내에서 실행되는 작은 실행단위 (하나의 프로세스 내 여러 스레드 존재)
특징
- 같은 데이터를 공유하므로 스레드간 통신이 빠르고 리소스(자원소비)를 적게 사용함
단점
- 메모리를 공유하므로 동기화가 잘못되면 (Race Condition 경쟁 조건)이 발생 가능.
- 하나의 스레드 오류로 전체 프로세스가 영향을 받을 수 있음.
- 파이썬에서 GIL (Global Interpreter Lock) 이 존재하여 한 번에 하나의 쓰레드만 실행될 수 있는데 이 때문에 CPU 집약적인 작업에서는 멀티스레딩이 병렬 처리의 이점을 얻지 못함
✅ 쓰레드는 같은 메모리 공간을 공유한다는 말이 무엇인가?
→ 그래서 한 쓰레드가 어떤 데이터를 수정하고 있을 때, 다른 쓰레드도 동시에 그 데이터를 읽거나 쓸 수 있음을 뜻한다.
✅ 동기화(Synchronization)는 무엇인가?
→ 여러 쓰레드가 공유 자원(예: 리스트, 변수 등)에 동시에 접근하지 않도록 제한을 거는 행위이다.
✅ 경쟁 조건 (Race Condition)이란 무엇인가?
→ 두 개 이상의 쓰레드가 동시에 같은 자원에 접근하고, 그 중 적어도 하나가 데이터를 수정할 때 발생하는 문제이다.
이 경쟁조건을 해결하기 위해서 동기화가 필요한 것이다. 파이썬의 경우는 threading.Lock() 같은 락(Lock)을 이용한다.
✅ 동기화를 해야 하는데, 같은 선상에 있는 쓰레드가 경쟁을 일으킨다는 게 무슨 말인가?
→ 같은 자원을 동시에 쓰려는 쓰레드들 사이에서 접근 타이밍이 겹치면 경쟁(race)이 발생한다.
그래서 동기화를 해야하는데 동기화는 한 번에 하나의 쓰레드만 자원에 접근하도록 "순서를 정해주는" 역할을 하는거다.
✅ 간단 정리
메모리 | 독립된 메모리 공간을 사용 | 메모리를 공유 |
자원 관리 | 독립적으로 자원 관리 | 프로세스 자원을 공유 |
병렬 처리 | 멀티코어에서 진정한 병렬 처리 가능 | GIL 때문에 한 시점에 하나의 쓰레드만 실행 (CPU 작업에서 병렬 처리 제한) |
속도 | 자원을 많이 사용하므로 상대적으로 느림 | 경량으로 빠름, 하지만 GIL에 의해 CPU 집약적인 작업에선 제한됨 |
통신 | IPC(Inter-Process Communication)가 필요 | 메모리 공유를 통해 쉽게 통신 가능 |
안정성 | 다른 프로세스와 독립적이므로 안정성 높음 | 메모리 공유로 인해 동기화 문제 가능 |
자원 소비 | 높은 메모리 사용 | 낮은 메모리 사용 |
프로세스를 사용해야 할 경우:
- 여러 작업이 독립적으로 실행되어야 할 때
- CPU 집약적인 작업에서 멀티코어를 최대한 활용하고 싶을 때
- 안정성이 중요한 경우 (프로세스가 다른 프로세스에 영향을 미치지 않음)
🔹 CPU 집약적인 작업이란?
예: 큰 수끼리 곱하기, 행렬 연산, 반복 루프 계산 등
🔹 멀티코어란?
요즘 컴퓨터나 서버는 CPU가 여러 개의 코어를 가지고 있음
예: 4코어, 8코어, 16코어…
- 코어 1개 = 한 번에 1가지 작업 가능
- 코어 4개 = 동시에 4개의 작업 수행 가능
🔹 CPU를 많이 쓰는 작업 = 수치 계산, 암호화, 이미지/영상 처리, 인공지능 연산 등
🔹 왜 멀티코어를 "최대한 활용"해야 할까?
파이썬에서는 threading을 써도 GIL(Global Interpreter Lock) 때문에
→ 한 번에 하나의 스레드만 실행됨
(즉, 여러 스레드를 만들어도 CPU는 실제로 하나만 씀)
그래서 "CPU 집약적 작업"에서는...
멀티스레딩은 효과가 없고,
멀티프로세싱이 필요하다!
멀티프로세싱을 쓰면, 각 프로세스는 GIL의 영향을 받지 않고,
→ 각자 독립적인 코어에서 실행할 수 있다.
→ 이게 바로 멀티코어를 최대한 활용하는 것이다.
쓰레드를 사용해야 할 경우:
- I/O 작업(파일 읽기/쓰기, 네트워크 요청 등)을 동시에 처리할 때
- 프로세스 간 통신이 필요 없고, 빠른 실행이 필요할 때
- 상대적으로 적은 메모리를 사용하는 애플리케이션을 만들고 싶을 때
🔸 I/O 작업이란?
→ Input/Output 작업, 즉 입출력 작업을 뜻한다 → 컴퓨터에서 "CPU 외부와 데이터를 주고받는 모든 작업"
-
- I/O 작업 종류예시
파일 I/O 파일 읽기/쓰기, 로그 저장 등 네트워크 I/O 웹 API 요청, 소켓 통신, DB 요청 등 디스크 I/O SSD/HDD로부터 데이터 읽기/쓰기 사용자 입력 키보드 입력, 마우스 클릭 등 (GUI/CLI)
- I/O 작업 종류예시
🔸 왜 I/O 작업이 문제인가?
CPU가 직접 계산하지 않고,
"외부 자원"과 데이터를 주고받는 작업이기 때문에 아래의 흐름으로 진행되어 느림
- CPU가 요청을 보냄
- 서버에서 응답이 올 때까지 "기다려야" 함
- 응답이 오면 다음 코드로 넘어감
이 기다리는 동안 → CPU는 놀고 있음 😴
→ 이런 걸 블로킹(blocking)이라하는데 이를 방지하기 위해서
멀티스레딩 or 비동기(asyncio)를 사용!