Skip to content

학습 노트: Python GIL과 check-then-act 레이스 컨디션 #2

Description

@cmygray

배경

#1 디버깅 과정에서 정리한 Python 멀티스레딩 학습 내용.

GIL이 있어도 레이스 컨디션은 발생한다

GIL이 보장하는 것

  • 단일 바이트코드 명령어의 원자성 (예: STORE_SUBSCRdict[key] = value)
  • interpreter 내부 자료구조의 무결성 (crash 방지)

GIL이 보장하지 않는 것

  • 여러 바이트코드에 걸친 논리적 원자성

check-then-act 패턴

# 이 코드는 3개의 바이트코드 명령어로 컴파일된다
if state["pressed"] and not state["holding"]:   # ① 읽기 (LOAD)
    state["holding"] = True                       # ② 쓰기 (STORE)
    on_start()                                    # ③ 부수효과 (CALL)

GIL은 ①과 ② 사이에서 스레드를 전환할 수 있다. 다른 스레드가 이 틈에 같은 state를 변경하면 논리적 불일치가 발생한다.

GIL 전환 조건

  • 5ms 간격: sys.getswitchinterval() 기본값 = 0.005초
  • I/O 블로킹: 파일, 네트워크, sleep 등 호출 시 즉시 전환

안전/위험 판단 기준

안전 (단일 명령) 위험 (복합 연산)
state["x"] = 1 if state["x"]: state["y"] = ...
dict[key] 단일 읽기 여러 키를 읽고 그 결과로 분기
list.append(x) if x not in list: list.append(x)

결론

GIL은 interpreter crash 방지이지, 비즈니스 로직의 원자성 보장이 아니다. check-then-act 패턴은 언어와 무관하게 항상 lock이 필요하다.

참고

  • CPython GIL 문서
  • dis 모듈로 바이트코드 확인 가능: python -m dis -c "d={'a':1}; d['a']=2"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions