GIL(Global Interpreter Lock)

Copes·2023년 1월 1일
0

Python

목록 보기
7/7

GIL이란?

  • 파이썬 인터프리터가 한 스레드만 하나의 바이트코드를 실행시킬 수 있도록 해주는 Lock

GIL의 목적?

파이썬은 기본적으로 레퍼런스 카운팅을 사용하는데,

이 레퍼런스 카운트 변수가 멀티스레드 환경에서 Race Condition을 야기할 수 있기 때문에

하나의 공통된 자원을 여러 스레드에서 접근하여 발생하는 이런 문제를 예방하기 위해서 GIL 사용

Critical Section

  • 병렬프로그래밍에서 둘 이상의 스레드가 동시에 접근해서는 안되는 공유 자원을 접근하는 명령문 또는 코드의 일부 영역

Race Condition

  • 두 개 이상의 프로세스(혹은 스레드)가 공통 자원을 병렬적으로 읽거나 쓰는 동작을 할 때,
    공용 데이터에 대한 접근이 어떤 순서에 따라 이루어졌는지에 따라 실행 결과가 같지 않고 달라지는 상황을 말한다.

Mutex

보통 GIL을 Mutex로 사용. (Cpython 코드)

static void take_gil(PyThreadState *tstate) {
	...
	MUTEX_LOCK(gil->mutex):
	...
	while (_Py_atomic_load_relaxed(&gil->locked)) {
		...
		int timed_out = 0;
		COND_TIMED_WAIT(gil->cond, gil->mutex, interval, timed_out);
		...
	}
	...
}

GIL 사용 시 멀티스레드 성능?

  • GIL에 의해 공유자원에 동시 접근하지 못해서 싱글 스레드와 유사하거나 overhead로 인해 더 느려질 수 있다.
  • 그러나, GIL을 사용하는 이유는 공유 자원에 접근해서 읽고 쓰는 것으로 인한 Race Condition 때문이므로, GIL을 사용하지 않고 다른 스레드가 CPU Bound Job을 수행할 수 있도록 GIL을 해제하고 I/O Bound Job(ex) download, print 작업 등)을 수행하여 이점을 볼 수 있다.

멀티 스레드 대신 멀티 프로세스를 사용한다면?

  • 스레드에 비해 프로세스는 무거운 자원이므로 부담스러울 수 있다.
  • 남용한다면 overhead로 인해 더 많은 시간이 소요될 수 있다.

C-Bindings

  • 동일하게 GIL에 의해 Lock이 걸리므로 성능 상의 이점을 보기 어렵다.
  • 다른 스레드가 다른 작업을 수행할 수 없으므로 직접 해제를 해야 한다.

해결 방법

1. Per-Interpreter (PEP 684)

  • 인터프리터를 여러 개 사용.
  • 프로세스와 유사해보일 수 있으나, Process는 OS 자원이므로 커널과 유저 스페이스의 Context Switching으로 많은 비용을 요구하지만
    인터프리터는 파이썬 런타임 내에 존재하는 개념이므로 상대적으로 Context Switching을 줄일 수 있다.

2. nogil flag

  • 멀티스레드 환경에서 CPU Bound 작업 시에도 효율적으로 동작 - Atomic Operator 때
  • Atomic Operator : 원자 단위로 작업 수행 가능

example

전자는 세 개의 단계로 이루어져서 중간에 다른 스레드가 해당 변수를 읽게 되면 문제가 발생할 수 있다.

반면, 후자인 Atomic Operator는 해당 문제를 해결할 수 있다.
(원자 단위 작업, LOCK ADD로 인해 Low Level에서 다른 스레드 접근 방지)

Reference)

  • PyCon Korea 2022

0개의 댓글