GIL란

**GIL(Global Interpreter Lock)**는CPython 인터프리터 전체를 감싸는 단 하나의 뮤텍스

핵심 효과는 하나로 요약:

어떤 시점에도 Python 바이트코드를 실행하는 스레드는 정확히 하나뿐, 스레드를 100개 띄워도 바이트코드 실행 권한(eval loop 진입권)은 GIL을 쥔 한 스레드만 가짐

[단일 스레드]
GIL: ████████████████████  (한 번 잡고 끝까지)
실행: a+b → b+c → c+d

[멀티 스레드, CPU 작업]
GIL: ███A███ ██B██ ███A███ ██B██   (5ms마다 번갈아)
     → 코어는 여러 개여도 실제 실행은 한 번에 1스레드
     → 그래서 CPU 병렬 이득이 없음

JVM에서는 이러한 구조가 아님.

JVM은 이런 전역 락이 없어서 스레드가 진짜로 여러 코어에서 병렬 실행

Python에서 threading 으로 CPU 작업을 돌렸을 때 코어가 하나 밖에 안 붙는 그 경험이 GIL 때문.

스레드를 100개 띄워도 바이트코드 실행 권한을 GIL을 쥔 한 스레드만 가짐

왜 존재하는가

근본 원인은 CPython의 메모리 관리 방식

CPython은 reference counting으로 메모리를 관리

이러한 배경은 CPython은 1990년 초에 만들어졌는데, 시대의 흐름 상 구현이 단순한 참조 카운팅으로

참조 생기면 +1, 사라지면 -1, 0되면 해제”로 단순하게 구현이 가능했기 때문.

객체에 접근할 때마다 Py_INCREF / Py_DECREF 로 refcount를 올리고 내림.

이 refcount 증감이 스레드 안전하지 않으면, 두 스레드가 동시에 같은 객체를 건드릴 때 카운터가 깨져서 → 메모리 누수 or 조기 해제 → 크래시

여기서 선택지는 2가지 였는데,

  1. 객체마다 락을 거는 fine-grained 방식
  2. 인터프리터 전체에 굵은 락 하나

어떻게 스레드를 전환하는가

GIL을 쥔 스레드가 바이트코드를 돌리는 동안 나머지는 락에서 블록