요약
- python 3.12 부턴 greenlet 사용하기 어려움
본문
Python 버전별 gevent 성능 벤치마크
Python 버전 업그레이드 시 gevent 스택 성능 영향을 측정하여 업그레이드 판단 근거를 확보하기 위한 실험.
실험 환경
| 항목 | 값 |
|---|---|
| 플랫폼 | Docker linux/amd64 (프로덕션과 동일 아키텍처) |
| gevent | 25.9.1 (3.9만 24.2.1) |
| greenlet | 3.4.0 (3.9만 3.2.5) |
| 반복 횟수 | 5회 (중앙값 기준) |
| 실행일 | 2026-04-15 |
Mac ARM64에서 QEMU 에뮬레이션으로 실행되므로 절대값보다 버전 간 상대 비교가 의미 있음.
벤치마크 항목
| 벤치마크 | 측정 대상 | 파라미터 |
|---|---|---|
greenlet_switch |
순수 greenlet.switch() 속도 |
200만 회 switch |
gevent_socket_echo |
gevent TCP echo 처리량 | 100 클라이언트 x 200 메시지 (64B) |
gevent_http_pool |
gevent HTTP RPS | 2000 요청, 동시 50개 |
결과
greenlet context switch (us/op, 낮을수록 좋음)
3.9 ██████████ 0.506 μs (baseline)
3.10 ████████████████ 0.804 μs +59% ← 현재 버전
3.11 ███████████████ 0.763 μs -5% vs 3.10
3.12 ███████████████████ 0.966 μs +20% vs 3.10
3.13 █████████████████ 0.859 μs +7% vs 3.10
TCP echo (msgs/sec, 높을수록 좋음)
3.9 █████████████████ 44,898
3.10 ████████████████████ 52,949 ← 현재 버전
3.11 ███████████████████ 50,069 -5%
3.12 ██████████████████ 46,333 -12%
3.13 ████████████████████ 54,002 +2%
HTTP RPS (높을수록 좋음)
프로덕션에 가장 가까운 지표.
3.9 ████████████████ 2,188
3.10 █████████████████ 2,337 ← 현재 버전
3.11 ███████████████████ 2,638 +13%
3.12 █████████████████ 2,355 +1%
3.13 ███████████████████ 2,568 +10%
종합
| 버전 | greenlet switch | HTTP RPS | 판정 |
|---|---|---|---|
| 3.10 → 3.11 | -5% (개선) | +13% (개선) | 업그레이드 추천 |
| 3.10 → 3.12 | +20% (악화) | +1% (무의미) | 비추천 |
| 3.10 → 3.13 | +7% (악화) | +10% (개선) | greenlet 불안정 |
분석
3.11이 좋은 이유
CPython 3.11의 specializing adaptive interpreter가 인터프리터 루프 자체를 최적화하여, greenlet switch 오버헤드를 상쇄하고도 HTTP RPS가 +13% 향상됨.
3.12에서 greenlet이 느려지는 이유
CPython 3.11부터 Python 프레임을 _PyInterpreterFrame이라는 경량 구조체로 재설계하기 시작함 (Faster CPython / PEP 659). greenlet은 C 스택을 통째로 swap하는 방식으로 동작하는데, 프레임 구조가 바뀌면서 context switch 시 추가 저장/복원 작업이 필요해짐.
3.11에서는 specializing adaptive interpreter의 성능 이득이 이 오버헤드를 상쇄하고 남았지만, 3.12에서 프레임 변경이 더 깊어지면서 (comprehension inlining, free-threading 준비 본격화) greenlet context switch 비용이 +20% 증가하고 상쇄가 불가능해짐.
이 변경은 free-threading(nogil) 준비를 위한 구조적 변화이므로 후속 버전에서도 해소되지 않음. (참고: gevent/gevent#1928)
3.12 HTTP RPS가 거의 차이 없는 이유
CPython 인터프리터 자체 성능 향상이 greenlet 저하를 딱 상쇄할 정도. 즉 gevent 스택의 이득이 0에 수렴하며, 버전이 올라갈수록 상황이 악화될 가능성이 높음.
결론
- 3.11 업그레이드: gevent 유지한 채 성능 이득 확보 가능
- 3.12+ 업그레이드: gevent → asyncio 전환이 선행되어야 함
3.11 업그레이드 시 블로커
- gunicorn 20.1.0 → 22.0.0+ 업그레이드
- django-mysql-geventpool 0.2.5 유지보수 중단 대응 (포크 교체 또는 django-db-geventpool)
참고
https://github.com/gevent/gevent/issues/1928 python 3.12부턴 cpython stack이 PyInterpreterFrame으로 관리된다. https://github.com/junha6316/gevent-pyver-benchmark