GIL(Global Interpreter Lock)
Garbage Collection 시스템은 다수의 thread가 함께 동작할 때 race condition으로 인한 문제가 생길 수 있습니다. 예를 들어 refcnt=5인 객체 X가 있다고 해봅시다. X를 A와 B 서로 다른 두 개의 thread가 접근하려고 합니다. 이 때 두 작업이 미세한 시간 차이로 이 X의 refcnt 값을 가져올 수 있습니다.
각자 X를 참조하였으니, refcnt를 1만큼 증가시킬 것입니다. 하지만 A와 B 모두 refcnt=5 일 때 가져왔으므로, 최종적으로 반환하는 refcnt는 7이 아니라 6이 됩니다. 이런 사고를 방지하려면 한 번에 하나의 스레드만 작업할 수 있도록 보장해야 합니다.

이 역할을 GIL이 할 수 있습니다. GIL은 CPython*에서 작동하는 인터프리터 수준의 잠금장치(lock)로, 한 줄의 byte code에 대한 lock을 보장합니다. lock을 보장함으로서 한 번의 작업에는 하나의 thread만 들어올 수 있게 됩니다.
*CPython : Python이 인터프리터에 의해 실행될 수 있도록 컴파일되는 중간 단계 언어
GIL은 CPython 수준에서 적용되는 것이기 때문에, 사용자가 직접 무언가를 설정할 필요는 없습니다.
threading.lock()
GIL이 있다고 해서 race condition을 완전히 방지할 수 있는 것은 아닙니다. GIL은 byte code 한 줄에 대한 원자성만 보장할 뿐, 여러 줄로 이루어진 논리적 작업은 보호하지 못하기 때문입니다. 간단한 예로, x += 1 이라는 한 줄의 코드는 사실 아래와 같은 byte code의 묶음으로 이루어져 있습니다.
- 1. 메모리에서 x 읽기
- 2. x의 값 1 증가
- 3. 메모리에 x 쓰기

GIL은 이 중 한 단계가 진행되는 동안만 thread의 접근을 통제합니다. 따라서 이 세 줄의 byte code 전체를 한 번에 하나의 thread만 이용할 수 있도록 하려면, threading 라이브러리의 Lock()을 사용해야 합니다.
lock = threading.Lock()
def deposit():
global balance
for _ in range(1000000):
with lock: # 여기서부터는 GIL과 상관없이 이 thread가 독점함
balance += 1
Lock은 코드 단위로 접근을 통제한다기 보다 특정 자원(변수, 상태값)에 대한 접근을 통제한다는 개념으로 사용됩니다. 위 코드의 경우 balance 변수에 대해 여러 thread가 한 번에 접근하지 못하도록 통제하고 있는 셈입니다.
GIL과 Lock의 비교
주방 시스템(Python 코드)과 그 주방 시스템을 사용하는 요리사(thread)들이 있다고 가정합시다.
GIL은 주방 시스템 자체에 걸어 놓은 자물쇠입니다. 한 번에 한 명의 요리사만이 열쇠를 받아 주방 시스템에 들어갔다 나올 수 있고, 요리사들은 들어가서 하나의 작업만 할 수 있습니다.
Lock은 요리사들이 같은 재료나 기구(데이터)를 두고 싸우지 않게 스스로 약속한 규칙입니다. 사용중이던 재료나 기구를 다른 요리사가 가져가면 곤란할테니, 적어도 그 재료를 이용한 조리를 마치기 전 까지는 다른 요리사가 사용할 수 없도록 하는 것입니다.
'Language > Python' 카테고리의 다른 글
| [Python] Closure (0) | 2026.02.15 |
|---|---|
| [Python] Garbage Collection (0) | 2026.02.15 |
| [Python] Syntax | 02. List (0) | 2026.02.15 |
| [Python] Syntax | 01. yield (0) | 2026.02.15 |
| [Python] Library | 07. boto3 (0) | 2025.12.31 |