Python
Generator, Decorator, GIL 등
멀티프로세싱은 어떻게 동작하는가
메모리 영역에서 어떤일이 발생하는가
오늘은 대망의 GIL이다.
요즘 Docker, 쿠버네티스 말고도 CS에서 벽을 느낀 계기가 있어서 CS 공부를 다시 살살 보고 있다. 학부시절, 정보처리기사, Topcit,..,등 을 공부했었는데, 그땐 단순 암기였다면 이번엔 이해하며 넘어가자는 마인드로 공부하고 있다. 근데 속도가 지금이 더 빠른 느낌.. 진작 이렇게 할걸
CS공부의 경우 타고타고 들어가는 느낌이 강해서 정리하면서 하기보다 일단 기초를 쌓고 다시 정리하는게 목표 ! 1일1정리가 목표였지만 안하고 있던 스스로에게 변명 한 번 했다.
여담이 길어졌다.
GIL 슬쩍 봤는데 Generator, Decorator와는 영역이 쫌 다른놈이다.
좀 더 파이썬의 근본으로 간 느낌이다.
GIL. 딱 처음 봤을때부터 감도 안오는 놈이었는데 global interpreter lock이랜다.
갑자기 이게 왜 궁금한데? 라고 물을 수 있겠지만, 스승님의 추천에는 이유가 있을터,, 쓸만한지 아닌지는 알고 난 뒤 내가 판단한다 ! 걱정 없으면 잊혀지고, 쓸만하면 기억에 남겠지..
일단 시작은 Python Docs !
한 번에 하나의 스레드만 실행하도록 보장하기 위해 CPython 인터프리터가 사용하는 메커니즘이라는데 동시 액세스로부터 암묵적으로 안전하게 함으로 CPython 구현을 단순화한다.
전체 인터프리터를 잠그는 것은 병렬성을 희생시키고 멀티 프로세서에 의해 제공되는 많은 병렬성을 희생시키면서 인터프리터가 멀티 스레드가 되는 것을 더 쉽게 만든다?!
외부 라이브러리의 압축이나 해싱과 같은 계산을 많이 필요로하는 작업에는 GIL을 해제하도록 설계되어있다.
시도해봤지만 단일 프로세서에서 성능저하 등이 보였고 구현하기 힘들었다?!
하나의 스레드만,, 실행하도록 보장한다매,,
이 글 마지막을 적고 있을때 다시 한 번 읽어보겠다.
역시 여기서 이해가 간다면 내가 아니지 :)
다시 열심히 구글링해보자.
python버전의 뮤텍스다.
race condition을 막고 thread safety를 보장한다.
I/O, Image processing 등은 GIL의 영향을 받지 않는다.
감자는 이해가 잘안되니까,, 예시를 한 번 보자 !
참고글
Python에서 A라는 스크립트를 실행하면 2개의 쓰레드가 생긴다고 해보자. 2개의 스레드를 1개의 코어시스템에서 돌린다면 동시에 돌아가는것처럼 보여도 당연히 cpu가 두 쓰레드를 번갈아가면서 처리한다. 특정 시점에서는 언제나 CPU는 단하나의 스레드만 처리하고 있다.
하지만 멀티코어 CPU라면? C와 같은 언어에서는 다중 코어라면 쓰레드가 여러 코어에서 동시에 실행될 수 있다. 하지만 GIL은 이걸 막고 있다 !
CPU가 100개여도 특정시점에서 파이썬 인터프리터를 사용하는 쓰레드는 언제나 1개라는 것이다.
race condition이란 ?
두 개 이상의 프로세스가 공통 자원을 병행적으로 읽거나 쓰는 동작을 할 때,
공용 데이터에 대한 접근이 어떤 순서로 이루어졌는지에 따라 결과가 다른 상황이다.
thread safety란 ?
멀티 스레드 프로그래밍에서 일반적으로 어떤 함수나 변수, 혹은 객체가 여러 스레드로부터 동시에 접근이
이루어져도 프로그램의 실행에 문제가 없음을 뜻한다.
안전하게 쓰려고 멀티스레드를 버린다니 ?! 그래도 되나?!
파이썬은 garbage collector와 reference counting을 이용하여 메모리를 관리한다.
이 때, 여러 쓰레드가 하나의 객체에 대한 참조 횟수를 공유하여 사용해야 하므로 문제가 생길 수 있다.
이를 해결하기 위해서는 각 객체에 대한 lock(ex. 세마포,뮤텍스)이 필요한데 너무 비효율적이다.
이러한 비효율을 막기 위해 GIL을 사용한다.
음.. 말로는 알겠는데 이해했다는 느낌이 안온다.
(라는 생각을 하며 다시 구글링하던중 빛과 같은 자세한 설명을 해주신 블로그의 글을 참고했다.)
파이썬 코드는 인터프리터를 통해 실행된다.
파이썬의 객체는 덩치가 크고 refcount를 통해서 메모리 관리가 이루어진다.
객체에 참조가 생기거나, 해제될때마다 refcount를 +- 하는데 쓰레드 간에 공유하는 객체가 있다면 객체를 참조하는 연산(=)은 race condition이 되고 모든 객체에 대해서 참조가 증가 또는 감소될때 lock을 걸어야한다는 의미다. 즉, 모든 객체가 크리티컬 섹션이 된다 !
정수 변수 하나까지 객체로 다루는 파이썬에서 이렇게 객체마다 lock을 걸어야하는 작업은 매우 비효율 적일수밖에 없다. 그래서 파이썬은 인터프리터에 락을 걸어버렸다. 쓰레드가 몇개건, CPU코어에 관계없이 인터프리터를 사용하는 쓰레드는 오직 1개로 만들었다.
garbage collector,, 컴공나와서 흐지부지 공부한 학생이라면 와 분명 들어봤는데,, 싶은 그 단어.
1,2학년때도 공부 좀 할걸,,
garbage collector 란?
현대적인 언어네는 거의 필수로 존재하며 개발자의 생산성을 향상시켜준다.
C#,JS,Python 등의 언어는 GC를 기본적으로 제공하며, C,C++과 같은 언어에서는
malloc(), free() 와 같은 저수준의 메모리 관리 함수를 제공한다.
python에서 GC가 어떻게 작동하는지 알아보자.
참고한 블로그. 정리 대박이다..
파이썬에서 메모리 관리와 Garbage Collection은 두가지 측면이 있다.
python에서의 주요 garbage collection mechanism은 Reference counting 방식이다.
객체를 만들때마다 reference count가 생성된다.
여기서 참조 회수가 증가하는 시점은
참조 횟수를 확인할 수도 있다 !!
a = 'jodong2' 에서 하나,, b = a 에서 둘,, 세번째는?
sys.getrefcount() 함수에 a가 전달되고 있다 !
GIL에 관련해서 여러 블로그들을 보다보니 refcount가 많이 나와서 간략하게 정리해봤다.