Stay hungry, Stay foolish

Python - GIL(Global Interpreter Lock) 본문

Python

Python - GIL(Global Interpreter Lock)

Jake2 2022. 10. 1. 12:58

어느날 파이썬으로 프로그래밍을 하게된 날, 개발 공부를 python으로 시작했다고 말씀드리니 CTO 님께서

GIL에 대해 아는지 여쭤보시더군요

?? GIL ??

I don'know what is it..

But, That word is rings a bell...

GIL 이라는 단어 파이썬 공부를 했다면 뭔가 설명은 못하더라도 들어본것 같기는 합니다.

파이썬에서 GIL 모르면 파이썬 모르는거다 라고 까지 말씀을 해주시니 자세히 알아봐야겠다라고 생각했는데,

감사하게도 이번 파이콘에 세션 주제로 있더라구요!

해당 내용을 정리해보겠습니다!


먼저 GIL은 Global Intrepreter Lock의 약자인데 Lock은 여러 워커가 동시에 동일한 자원에 접근을 할 때 Violation 이 발생 할 수 있는상황을 예방 하기 위해 통제를 하는것을 의미합니다.

이 여러 쓰레드(혹은 프로세스) 에서 동시에 접근 하는 영역을 Critical Section 이라고 표현을 하구요.

이 Critical Section에 해당되는 자원에 Lock / Thread Safe 한 작업을 해줘야 합니다.

 

Python gabage collection  위해서 사용하는 방식은 Reference Counting 이라는 방식을 사용하는데 이게 뭐냐면 변수를 참조하는 변수의 개수를 세고 이것이 0 될때 메모리가 정리되는 방식입니다.
(GC - gabage collection  사용되지 않는 메모리를 정리해주는 기능입니다)


근데 이 ref_cnt 자체도 변수입니다. 그리고 이 변수가 Critical Section 이 되고 Multi Thread 환경에서는 충분히 Violation 이 일어날 수 있게됩니다. 그렇게 되면 메모리 릭이 발생하고 참조하는 변수가 없음에도 ref_cnt 가 0이 되지 않을 수 있다!

Multi-core program에서 가장 자주 발생하는 Violation은 Race Condition 입니다.

그러면 이 Race Condition 이 어떻게 발생하게 되는지 깊게 살펴보겠습니다.

Python 에서 변수 x += 1 을 해준다고 했을때 

위의 어셈블리어 처럼 3가지의 최소한의 동작으로 변수에 1을 더해주는 작업이 진행되는데요.


1. num 을 계산하기 위해 산술 레지스터의 eax를 불러오고(LOAD)
2. 산술레지스터에 1을 더하도록(INC) 명령하고
3. 계산된 결과를 다시 변수(num)으로 저장(STORE)시키는 과정을 거친다.

즉 두 thread 에서 Critical Section에 동시 접근 한다고 했을때 

위의 이미지처럼 두 thread T1과 T2에서 동시성 보장을 위해 context switching이 발생하며 결과적으로 2가 되어야할 ref_cnt 가 1로 저장되는 결과가 발생하는 것입니다.


이런 MultiThread 환경에서 발생할 수 있는 문제를 대응하기 위한 대표적인 방법으로는 Mutex Lock 이 있습니다.

Mutex Lock 은 공통된 자원에 하나의 thread 만 점유가 가능토록 lock을 걸어주는건데 이 Thread 가 변수에 대한 작업이 종료되면 lock을 해제시켜 다른 thread 에서도 해당 변수에 접근 가능토록 시키고 이렇게 함으로써 data 동기화에 대한 문제를 해결 할 수 있습니다.

 

Python의 대표적인 인터프리터인 CPython에서  실제로 gil이 돌아가는 Mutex lock의 코드를 보면

lock이 해제 될때까지 while 문을 통해 무기한 기다리고 있는것을 볼 수 있습니다.

 

파이썬 GIL 은 사실 파이썬 인터프리터 안에서 존재한다고 볼 수 있는데 이 인터프리터 안에 변수, 함수 정보들이 존재하고 인터프리터 내에서 상호작용하며 코드가 실행됩니다. 그렇기 때문에 글로벌 환경에서 mutex lock 이 작용이 되는건데 race condition 에 대한 대응책은 되지만 다른 thread 가 대기하게 되면서 성능에서의 낭비가 있을 수 있다는게 GIL의 단점이라고 할 수 있습니다.

 

정리하자면 GIL 은 global interpreter lock 이라는 이름그대로 python 인터프리터에서 제공하는 기능으로 python이 멀티 쓰레드 환경에서 동일한 자원에 접근할때 전역 global 로 mutex lock을 지원하는 기능이다!
이 덕분에 python의 여러 쓰레드에서 동시 접근할 수 있는 gc의 ref_cnt 변수도 제대로 된 결과 값을 보장받을 수 있는것이다.
하지만 다른 thread가 해당 자원에 대한 lock을 해제할때까지 또다른 thread는 while 문 속에서 무기한 대기를 해야하므로 성능에서 낭비가 있을 수 있다.

 

읽어주셔서 감사합니다! 


Reference

- Pycon 2022 GIL 톺아보기

'Python' 카테고리의 다른 글

내가 쓰려고 만든 원티드 북마크 자동 지원  (0) 2021.09.01
Comments