
파이썬에서 "왜 멀티스레딩을 써도 빨라지지 않지?"라는 질문은 오래된 단골 질문입니다. 그 중심에는 GIL(Global Interpreter Lock)이 있습니다. 이번 글에서는 멀티프로세싱과 멀티스레딩의 차이, 그리고 2026년 현재 매우 중요한 변화인 파이썬 3.14의 프리스레딩(free-threading) 지원까지 함께 정리합니다.
1. 기본/개요: GIL이 만든 오래된 제약
GIL은 CPython 인터프리터가 한 번에 하나의 스레드만 파이썬 바이트코드를 실행하도록 강제하는 뮤텍스(잠금 장치)입니다. 이는 파이썬 객체의 레퍼런스 카운트가 여러 스레드에서 동시에 변경될 때 발생할 수 있는 메모리 손상을 막기 위해 CPython 초기부터 도입된 설계입니다. 이 때문에 threading 모듈로 스레드를 아무리 많이 만들어도, CPU 연산이 많은 작업(CPU-bound)에서는 실제로 동시에 실행되지 않고 번갈아 실행되는 구조였습니다. 반면 multiprocessing은 여러 개의 독립된 프로세스를 띄우는 방식으로, 프로세스마다 별도의 인터프리터와 GIL을 가지므로 진짜 병렬 실행이 가능했습니다. 대신 프로세스 간 통신(IPC), 데이터 직렬화(pickling), 프로세스 생성 비용이라는 대가를 치러야 했습니다.
개인적으로 느끼는 점: 지난 수십 년간 "CPU 바운드면 멀티프로세싱, I/O 바운드면 멀티스레딩"이라는 공식은 파이썬 개발자에게 거의 상식처럼 통했습니다. 그런데 이 공식이 최근 크게 흔들리고 있다는 점이 이 주제에서 가장 중요하게 짚어야 할 부분이라고 생각합니다.
2. 기능/스펙: threading, multiprocessing, 그리고 프리스레딩
threading 모듈은 실제 OS 스레드를 사용하지만, GIL이 활성화된 기본 빌드에서는 한 번에 하나의 스레드만 바이트코드를 실행합니다. I/O 작업 중에는 GIL이 해제되므로 I/O 바운드 작업에는 상대적으로 영향이 적습니다.
multiprocessing 모듈은 여러 프로세스를 생성해 각각 독립적인 메모리 공간과 인터프리터를 사용하므로 CPU 여러 코어를 동시에 활용하는 진짜 병렬 처리가 가능합니다. 다만 프로세스 간 데이터 공유가 직렬화를 거쳐야 하므로 오버헤드가 발생합니다.
가장 중요한 최근 변화는 PEP 703 기반의 프리스레딩(free-threading) 빌드입니다. 공식 문서에 따르면 CPython은 3.13 릴리스부터 GIL을 비활성화한 빌드를 지원하기 시작했고, 3.14에서는 이 기능이 공식적으로 지원되는 단계로 발전했습니다. 프리스레딩 빌드에서는 여러 스레드가 사용 가능한 CPU 코어에서 진짜로 병렬 실행되어 처리 능력을 온전히 활용할 수 있습니다. 다만 모든 소프트웨어가 자동으로 이 이점을 누리는 것은 아니며, 확장 모듈(C 익스텐션) 중 일부는 아직 프리스레딩에 대응하지 못해 GIL을 강제로 다시 활성화시키는 경우도 있습니다. 공식 문서는 pyperformance 벤치마크 기준으로 프리스레딩 빌드의 단일 스레드 실행 오버헤드가 macOS aarch64에서 약 1%, x86-64 리눅스에서 약 8% 수준이라고 밝히고 있습니다.
비판적으로 보면: 프리스레딩은 아직 완전히 성숙한 기본값이 아닙니다. C 확장 모듈 생태계가 프리스레딩을 지원하도록 갱신되는 데는 시간이 걸리며, 지원하지 않는 패키지를 임포트하면 GIL이 자동으로 재활성화될 수 있습니다. 즉 "GIL이 사라졌다"는 표현은 아직 절반의 진실이며, 실제 운영 환경 도입 전에는 사용 중인 의존성 패키지가 프리스레딩과 호환되는지 반드시 확인해야 합니다.
3. 장단점
멀티스레딩(threading) 장점
- 프로세스보다 생성 비용이 낮고 메모리를 공유해 가벼움
- I/O 바운드 작업(파일, 네트워크 대기)에서는 GIL의 영향이 상대적으로 적음
- 기본 GIL 빌드에서도 여전히 실무적으로 널리 쓰이는 안정적인 도구
멀티스레딩 단점
- 기본(GIL 활성화) 빌드에서는 CPU 바운드 작업에 실질적인 병렬 이득이 없음
- 프리스레딩 빌드는 아직 생태계 호환성이 완전하지 않음
멀티프로세싱(multiprocessing) 장점
- GIL과 무관하게 진짜 병렬 실행이 가능해 CPU 바운드 작업에 확실한 이득
- 프로세스가 완전히 격리되어 있어 한 프로세스의 오류가 다른 프로세스에 영향을 덜 줌
멀티프로세싱 단점
- 프로세스 생성 비용과 데이터 직렬화(pickling) 오버헤드가 큼
- 메모리를 공유하지 않으므로 대용량 데이터 교환 시 비효율적일 수 있음
- 실제로 어떤 벤치마크에서는 프리스레딩 빌드에서 오히려 멀티프로세싱보다 느린 결과가 나온 사례도 보고되고 있어, 작업 특성에 따라 우열이 달라질 수 있습니다.
제 생각: "무조건 프리스레딩이 정답"이라는 식의 성급한 결론은 경계할 필요가 있다고 봅니다. 실제 벤치마크들에서도 워크로드에 따라 결과가 엇갈리는 사례가 보고되고 있는 만큼, 특정 애플리케이션에 어떤 방식이 유리한지는 반드시 해당 워크로드로 직접 측정해서 판단해야 하는 문제라고 생각합니다.
4. 추천 대상
- 멀티스레딩 추천 대상: 파일 다운로드, 네트워크 요청처럼 I/O 대기가 많은 작업을 처리하는 개발자
- 멀티프로세싱 추천 대상: 대규모 수치 연산, 이미지·영상 처리 등 CPU 자원을 많이 쓰는 작업을 안정적인 방식으로 병렬화하려는 개발자
- 프리스레딩(3.13+) 시도해볼 대상: 최신 파이썬 환경을 직접 구축할 수 있고, 사용하는 라이브러리들의 프리스레딩 호환성을 확인할 여력이 있는 개발자. 단, 프로덕션 도입 전 충분한 테스트가 필요합니다.
5. FAQ
Q1. GIL이 완전히 사라졌나요?
A. 기본 빌드에서는 여전히 GIL이 활성화되어 있습니다. GIL이 없는 프리스레딩 빌드는 3.13부터 실험적으로, 3.14부터 공식적으로 제공되는 선택 옵션이며, 기본값으로 완전히 대체된 것은 아닙니다.
Q2. 프리스레딩 빌드를 쓰면 무조건 빨라지나요?
A. 아닙니다. 워크로드 특성과 사용하는 라이브러리의 호환성에 따라 결과가 달라집니다. 순수 파이썬 CPU 연산에서는 유의미한 속도 향상이 보고된 사례가 많지만, 반대로 특정 벤치마크에서는 멀티프로세싱이 더 빠른 경우도 보고되었습니다.
Q3. multiprocessing과 threading 중 무엇을 먼저 배워야 하나요?
A. 둘 다 표준 라이브러리이므로 상황에 따라 선택해서 쓸 수 있도록 개념 자체는 함께 익혀두는 것이 좋습니다. 다만 처음 접한다면, 먼저 I/O 바운드/CPU 바운드 작업의 차이를 이해하는 것이 두 도구를 올바르게 구분해 쓰는 데 더 중요합니다.
Q4. 프리스레딩 빌드는 어떻게 설치하나요?
A. 배포판마다 설치 방법이 다르며(예: 특정 빌드 태그가 붙은 인터프리터 설치), 세부 절차는 사용 중인 운영체제와 배포 방식에 따라 달라지므로 이 글에서 일률적으로 안내하기는 어렵습니다. 파이썬 공식 문서의 프리스레딩 지원 안내를 참고하는 것을 권장합니다.
Q5. asyncio도 이 비교에 포함되나요?
A. asyncio는 단일 스레드에서 협력적으로 동작하는 방식으로, 멀티스레딩·멀티프로세싱과는 접근 방식이 다릅니다. I/O 바운드 작업에서 매우 효율적이지만 여러 CPU 코어를 직접 사용하지는 않습니다.
6. 출처
- Python 공식 문서, "Python support for free threading" (docs.python.org)
- Towards Data Science, "Python 3.14 and the End of the GIL"
- danilchenko.dev, "Python 3.14 Free-Threading: Real Benchmarks, Real Breakage, Real Code"