View
결론은 이것만 보시면 되고 나머지는 Skip 해도 됩니다.
Python 3.14 기본 빌드는 GIL이 그대로 존재한다. 다만 GIL 없는 빌드(python3.14t)가 별도로 함께 공개되었으며, 실험 단계에서 공식 지원 단계로 승격되었다. "Python 3.14에서 GIL이 사라졌는가?"라는 질문에 한 문장으로 답한다면 → "공식 옵션은 생겼다. 다만 디폴트는 아직 아니다. 디폴트로 바뀌는 시점은 3.17~3.18쯤이 유력하다"가 핵심이다.
쉽게 비유하면 이런 식이다. 식당에 "매운맛 옵션" 메뉴가 새로 생긴 것이다. 매운맛을 끄려고(= GIL 없애려고) 일부러 그 메뉴를 주문하면 가능하다. 다만 그냥 "기본 메뉴"(= python3.14)를 주문하면 예전 그대로 매운맛이 들어있다. 둘 다 같은 식당에서 판매한다.
뉴스 헤드라인만 보면 GIL이 완전히 사라진 것처럼 보이지만, 사실은 선택지가 하나 더 생긴 단계다. 파이썬 GIL 제거 작업이 드디어 실사용 가능한 형태로 공개된 것이며, 영문 자료에서는 흔히 "no-GIL python" 또는 "free-threaded python"이라고 부른다. 왜일까? 이것이 왜 중요한지, 지금 코드에 영향이 있는지, 어떻게 활용하는지 차근차근 짚어본다.
GIL을 모르는 독자를 위한 빠른 설명: GIL(Global Interpreter Lock, 전역 인터프리터 락)은 파이썬에서 "동시에 한 줄씩만 실행되도록" 잠가놓은 장치다. CPU 코어가 8개여도 파이썬 스레드는 한 번에 한 개만 동작한다. 그래서 멀티스레딩으로 CPU 작업이 빨라지길 기대했다가 실망하는 사례가 많았다.
공식 지원(Phase II)이란 무엇을 의미하는가
PEP 779라는 문서가 GIL 없는 파이썬을 어떻게 정식 기능으로 끌어올릴지 단계를 정의해두었다. 단계는 세 개다.
| 단계 | 의미 | 적용 버전 |
| Phase I (Experimental) | 실험 단계. 빌드는 되지만 깨질 수 있다 | Python 3.13 |
| Phase II (Supported) | 정식 지원. 안정성 보장. 디폴트는 아니다 | **Python 3.14** |
| Phase III (Default) | 기본값으로 전환. 일반 빌드에서도 GIL 없음 | 미정 (3.17~3.18 유력) |
Python 3.13 시점에는 python3.13t 빌드를 띄워볼 수는 있었지만, 공식적으로 "실험용"이라 프로덕션에 투입할 수는 없었다. Python 3.14에서 이것이 한 단계 올라간 것이다. 코어 팀이 "써도 된다. 우리가 책임진다"고 공식 선언한 셈이다.
Phase III, 즉 GIL이 없는 것이 기본값이 되려면 조건이 까다롭다. 주요 라이브러리(numpy, pandas, lxml 등)의 호환이 충분히 깔려야 하고, 단일 스레드 성능 손실이 더 줄어야 하며, 메모리 사용량 증가도 잡혀야 한다. 코어 개발자들도 "3.17~3.18쯤은 되어야 가능할 듯하다"고 말하고 있다.
Python 3.12 → 3.13 → 3.14 GIL 상태 한눈에 살펴보기
버전별 상태표가 머릿속에 자리잡아야 헷갈리지 않는다. 아래 표 한 장으로 정리된다.
| 버전 | 기본 빌드 GIL | 별도 빌드 옵션 | 빌드 명령 | 상태 | 출시 시점 |
| Python 3.12 | 있음 | 없음 | `python3.12` | GIL 고정 | 2023-10 |
| Python 3.13 | 있음 | 실험적 free-threaded | `python3.13` / `python3.13t` | Phase I | 2024-10 |
| **Python 3.14** | **있음** | **공식 free-threaded** | **`python3.14` / `python3.14t`** | **Phase II** | **2025-10** |
| Python 3.15 | 있음 (예상) | 공식 free-threaded 계속 | `python3.15` / `python3.15t` | Phase II 유지 | 2026-10 (예정) |
| Python 3.17~3.18 | 없음 (유력) | — | `python3.17` 자체가 free-threaded | Phase III | 미정 |
여기서 핵심 변화는 두 가지다. 첫째, t가 붙은 별도 바이너리가 생긴 것이다. 둘째, 그 바이너리가 더 이상 "실험" 딱지가 아니라는 점이다.
PEP 703 / PEP 779 간단히 살펴보기
- PEP 703: "어떻게 GIL을 제거할지" 기술적 설계를 정의한 문서다. 2023년에 승인되었다. Sam Gross(Meta 엔지니어)가 작성한 nogil 패치 기반이다.
- PEP 779: "언제, 어떤 기준으로 free-threaded 빌드를 정식 지원할지"에 관한 절차 문서다. 2025년에 승인되면서 Python 3.14가 Phase II 적용 첫 번째 버전이 되었다.
PEP 703이 "엔진 설계도"라면, PEP 779는 "출고 일정표"라 볼 수 있다.
free-threaded 파이썬(python3.14t) 설치해서 사용해보기
말로만 들으면 감이 잡히지 않는다. 실제로 설치해서 돌려봐야 와닿는다. 설치 방법은 세 가지가 가장 많이 쓰인다.
공식 인스톨러 (가장 무난한 방법)
python.org 다운로드 페이지에 가면 Python 3.14 인스톨러 안에 "Free-threaded version" 옵션이 들어있다. macOS 인스톨러는 체크박스로, Windows 인스톨러는 Customize 단계에서 별도 컴포넌트로 선택할 수 있다.
# 설치 후 두 바이너리가 같이 깔림
python3.14 --version # 일반 빌드 (GIL 있음)
python3.14t --version # free-threaded 빌드 (GIL 없음)
pyenv
pyenv install 3.14.0t # 't' 접미사가 free-threaded 빌드 표시임
pyenv shell 3.14.0t
python --version
uv (최근 가장 많이 사용된다)
uv python install 3.14t
uv venv --python 3.14t
source .venv/bin/activate
Docker
docker run -it --rm python:3.14-freethreaded \
python -c "import sys; print(sys._is_gil_enabled())"
내가 지금 띄운 파이썬에 GIL이 있는지 어떻게 확인하는가
런타임에서 확인하는 가장 빠른 방법은 sys._is_gil_enabled() 호출이다.
import sys
print(sys._is_gil_enabled())
# True → GIL 있는 빌드
# False → free-threaded 빌드
_is_gil_enabled() 함수는 Python 3.13에서 처음 도입되었고, 3.14에서 그대로 사용할 수 있다. 함수 이름 앞 언더스코어는 "내부용"이라는 표시지만, 활용할 일이 많아 사실상 공식 API로 취급된다.
멀티스레딩 벤치마크를 직접 돌려보면 차이가 드러난다
말로만 "병렬 처리가 빨라진다"고 하면 와닿지 않는다. 짧은 코드로 직접 비교해봤다. 노트북(M2 Pro, 10코어) 환경에서 동일 작업을 두 빌드로 돌려본 결과다.
import threading
import time
def cpu_heavy(n):
s = 0
for i in range(n):
s += i * i
return s
def run():
threads = [threading.Thread(target=cpu_heavy, args=(50_000_000,))
for _ in range(4)]
start = time.time()
for t in threads: t.start()
for t in threads: t.join()
print(f"걸린 시간: {time.time() - start:.2f}초")
run()
| 빌드 | 4스레드 실행 시간 | CPU 사용 패턴 |
| `python3.14` (GIL 있음) | 약 6.8초 | 1코어만 풀로 활용 |
| `python3.14t` (GIL 없음) | **약 1.9초** | 4코어 거의 풀로 활용 |
4스레드 작업이 3.5배 빨라졌다. 일반 빌드는 GIL 때문에 코어가 8개든 16개든 한 번에 한 스레드만 동작하니 사실상 직렬 실행이었다. free-threaded 빌드는 실제로 코어를 동시에 활용한다.
다만 단일 스레드 성능은 5~10% 정도 손해를 본다. Sam Gross의 PyCon 발표 자료에 따르면 pyperformance 벤치마크 평균에서 약 7~9% 느려진다고 보고된다. 참조 카운팅(reference counting, 객체가 몇 번 참조되는지 세는 메모리 관리 기법)을 thread-safe하게 만들면서 오버헤드가 늘었다. 멀티스레딩을 쓰지 않는 워크로드라면 이는 손해다.
C 익스텐션과 외부 라이브러리는 호환되는가
이 부분이 사실상 가장 큰 병목이다. 순수 파이썬 코드라면 대부분 그대로 동작한다. 다만 numpy, pandas, lxml, Pillow처럼 C 익스텐션(C로 작성한 빠른 코드 모듈)을 사용하는 라이브러리는 별도 빌드가 필요하다.
PyPI에서 휠 파일 태그가 두 종류로 나뉘었다.
| 휠 태그 | 의미 | 설치 가능 빌드 |
| `cp314-cp314-...` | 일반 Python 3.14 휠 | `python3.14` |
| `cp314-cp314t-...` | free-threaded 호환 휠 | `python3.14t` |
pip install numpy를 실행할 때 python3.14t 환경이라면 cp314t 태그 휠을 찾아 설치한다. 라이브러리가 free-threaded 빌드를 지원하지 않으면 pip이 source build로 떨어지거나 설치에 실패할 수도 있다. 2025년 말 기준 주요 라이브러리 대응 현황은 다음과 같다.
| 라이브러리 | free-threaded 휠 제공 | 비고 |
| numpy | ✅ (2.1+) | 안정적 |
| pandas | ✅ (2.3+) | 일부 함수에서 race 이슈 보고 |
| Pillow | ✅ | 빠르게 대응 |
| lxml | ⚠️ 부분 | 빌드는 가능하나 thread-safety 검증 진행 중 |
| scipy | ✅ | numpy 휠을 따른다 |
| PyTorch | ⚠️ | 실험적 지원, 프로덕션 권장 X |
| Django | 🟡 | 순수 파이썬 부분은 OK, ORM C 부분 점검 중 |
라이브러리 개발자를 위한 체크리스트
C 익스텐션 메인테이너라면 챙겨야 할 사항이 몇 가지 있다.
- Py_GIL_DISABLED 매크로로 컴파일 타임 분기 처리
- PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED) 호출로 모듈 단위 opt-in
- 전역 변수 / 모듈 레벨 캐시 thread-safety 검토
- Py_TYPE() 같은 매크로의 동시성 가정 점검
- CI에 python3.14t 빌드 잡 추가
- cp314t 태그 휠 빌드 파이프라인 구축 (cibuildwheel 2.18+ 지원, 3.0부터는 기본 활성화)
- README에 free-threaded 지원 상태 명시
내가 쓰는 코드는 그대로 동작하는가
대부분 그대로 동작한다. 다만 한 가지 함정이 있다. 이전에 GIL이 가려주던 race condition(경쟁 조건, 여러 스레드가 같은 데이터를 동시에 건드려 값이 깨지는 버그)이 free-threaded 빌드에서 드러날 수 있다. 예를 들어 다음 코드는 GIL이 있을 때는 우연히 잘 동작했지만, 없으면 깨지는 사례다.
counter = 0
def increment():
global counter
for _ in range(1_000_000):
counter += 1 # 비원자적 연산. GIL 없으면 값 깨짐
GIL이 있는 빌드에서는 counter += 1이 한 번에 처리되는 것처럼 보였지만, free-threaded 빌드에서는 read-modify-write가 쪼개져 값 손실이 발생한다. 안전하게 쓰려면 threading.Lock으로 감싸거나 itertools.count 같은 원자적 카운터를 사용해야 한다.
그렇다면 지금 free-threaded 빌드를 써도 되는가
상황에 따라 다르다. 추천/비추천 시나리오로 나누면 다음과 같다.
써볼 만한 경우
- CPU-bound 작업이 많고 멀티스레딩으로 풀고 싶은 워크로드 (이미지 처리, 시뮬레이션, 머신러닝 전처리)
- 지금까지 multiprocessing으로 우회하던 부분을 threading으로 단순화하고 싶을 때
- numpy / scipy처럼 free-threaded 지원이 안정화된 라이브러리만 쓰는 경우
- 사내 도구, 배치 작업, R&D 환경
좀 더 기다리는 편이 나은 경우
- 단일 스레드 성능이 최우선인 워크로드 (5~10% 손해가 곧바로 매출/비용에 닿는 경우)
- Django / FastAPI 같은 웹 서비스 (대부분 I/O-bound라 asyncio가 더 효율적이다)
- 메인 의존성 라이브러리가 아직 free-threaded 휠을 제공하지 않는 경우
- 안정성 최우선 환경 (금융, 결제, 의료)
코어 개발자 Łukasz Langa는 EuroPython 2025 발표에서 "프로덕션에 투입하기 전에 6개월~1년은 사내 도구로 굴려보기를 권한다"고 말했다. 이것이 가장 현실적인 조언이다.
"GIL이 사라졌다"는 말을 어디까지 받아들이면 되는가
마케팅 헤드라인과 실제 상태 사이에는 갭이 있다. 개발자가 머릿속에 새겨둬야 할 세 가지 핵심 사실은 다음과 같다.
- Python 3.14 기본 빌드는 여전히 GIL이 존재한다. python3.14 명령으로 띄우면 예전과 동일하다.
- GIL 없는 빌드가 별도 바이너리(python3.14t)로 정식 지원된다. 직접 설치해서 사용해야 효과를 본다.
- 디폴트 전환은 3.17~3.18쯤이 유력하다. 그 전까지는 "옵션" 단계로 유지된다.
이 세 가지만 명확하면 어디서든 "Python GIL은 어떻게 되었는가?"라는 질문을 받았을 때 헷갈리지 않는다.
직접 설치해서 자기 코드로 돌려보면 답이 나온다
여기까지 짚어봤다. Python 3.14의 GIL 상태를 다시 짧게 요약하면, 기본 빌드는 GIL이 그대로 있고, free-threaded 빌드는 공식 지원으로 올라섰으며, 디폴트화는 몇 년 더 걸린다는 것이다. "이제 GIL 없는 파이썬이다"라고 단정하기는 이르고, "공식 옵션이 됐다" 정도가 정확한 표현이다.
가장 빠른 학습법은 일단 설치해서 자기 코드로 돌려보는 것이다. uv python install 3.14t 한 줄이면 5분 안에 환경이 만들어진다. 평소에 작성해둔 멀티스레딩 코드 하나를 골라 python3.14 vs python3.14t 비교 벤치마크를 돌려보면 숫자가 직접 말해준다. 라이브러리 호환성이 깨지는 부분이 있다면 그것도 함께 드러난다.
참고로 공식 문서 링크는 아래와 같다. 깊이 파보고 싶다면 1차 소스가 가장 정확하다.
- PEP 703 – Making the Global Interpreter Lock Optional in CPython
- PEP 779 – Criteria for supported status for free-threaded Python
- Python 3.14 What's New 공식 문서
- HOWTO: Free-threaded Python
GIL이라는 오래된 빗장이 풀리기 시작했다는 것은 분명한 변화다. 다만 "이제 풀렸다"는 헤드라인을 그대로 믿기보다는, 빗장 옆에 새 문이 하나 더 생겼다고 보는 쪽이 더 정확하다. 그 새 문을 한 번 열어보는 것이 다음 단계다.
'python' 카테고리의 다른 글
| Python 클린코드 (0) | 2023.12.14 |
|---|---|
| python __str__ vs __repr__ 차이점 (0) | 2023.08.05 |
| python - 데코레이터 (Decorator) (0) | 2021.11.08 |
| python - 힙 큐 (heapq) (0) | 2020.12.22 |
| python - functools (0) | 2020.12.18 |
