개발언어/Python

[Python] GIL

JiWonSon 2023. 9. 20. 17:40

1)GIL이란?

GIL은 파이썬 인터프리터에 한 갱의 Thread가 하나의 바이트 코드를 실행할 수 있도록 걸어두는 Lock이다.
하나의 Thread는 파이썬 인터프리터의 모든 자원을 사용하나, 다른 사용할 수 없도록 Lock을 걸어둔다는 의미이다.

 

 

예시)

import threading
x = 0
 
def foo():
    global x
    for _ in range(1000000):
        x += 1
 
def bar():
    global x
    for _ in range(1000000):
        x += 1
 
thread1 = threading.Thread(target=foo)
thread2 = threading.Thread(target=bar)
 
thread1.start()
thread2.start()
 
thread1.join()
thread2.join()
print(x)

 

위 코드는 x라는 공유된 변수에 thread1과 thread2가 동시에 접근해서 1씩 더하는 코드이다.

결과는 제각각이겠지만 2000000이 출력되어야 하는데 위 출력 결과는 1310848값이 출력된다.
이는 공유도니 변수에 두 쓰레드가 동시에 접근하면서 발생된 문제이다.
x += 1은 x=x_1이 축약된 문장인데, 우항의 x에 값을 대입하는 과정 중 다른 쓰레드가 값을 변경하면 이후 좌변의 x에 값을 대입할 땐 중간결과가 무시된다. 

요약하자면, 

1) Thread1 : x값 조회중

   Thread2 : 다른 작업중
2) Thread1 : x값 1더함
    Thread2 : x 값 조회
3) Thread1 : x 값 할당
    Thread2 : x 값 1더함
4) Thread1: 다른 작업중
    Thread2:  x 값 할당

 이렇다.
즉, 여러 쓰레드가 하나의 공유 자원이 동시에 접근하면서 발생하는 문제를 race condition(경쟁상태)라고 하며, 이 문제를 해결하기 위해 Mutex의 방안이 있다.

 Mutex는 이렇게 공유 자원에 하나의 쓰레드만 진입하며 작업을 처리할 수 있도록 만들어진 lock 개념이다. 간단히 비유하자면 한 사람만 이용할 수 있는 공중화장실은 출입문의 잠금장치를 열어야 이용이 가능하며 사람들은 줄 따위 서지 않고 호시탐탐 출입문을 노리고 있는 상황을 가정하자. 이용하고자 대기 중인 여러 사람이 Thread이고 화장실 시설이 resource, 화장실 출입문이 mutex, 화장실 출입문의 잠금장치가 lock이다.

 

2)파이썬은 멀티쓰레드 언어인가


* 싱글스레드언어

 

스레드가 하나인 언어로 javascript가 대표적이다.
파이썬도 병렬 처리를 위한 쓰레드를 갖고있긴하다.

운영체제가 cpu에 파이썬 스레드의 job을 할당하려면 커널레벨스레드(Native Thread)와 파이썬의 스레드를 1:1로 매핑시켜야하는데,

 파이썬은 GIL이라는 lock때문에 커널레벨 스레드는 파이썬의 하나의 프로세스와 매핑된다.

코드상의 로직은 동시에 진행되는것 같지만 하나의 cpu가 빠르게 왔다갔다하면서 스레드를 처리한다고 생각하면 된다.

파이썬은 멀티스레드언어로 불리기보다는 싱글스레드언어, 싱글코어 언어 등 동시에 하나의 CPU만 사용하는 언어로 불린다.

파이썬은 GIL때문에 하나의 프로세스가 동시에 하나의 코어밖에 사용하지 못하는 언어이다.


* 멀티스레드언어

 

스레드가 여러개인 언어로 java, c# 등이 있다.

멀티스레드언어는 운영체제가 스레드의 작업을 여러개의 cpu에 직접 할당할 수 있다.

 

3) CPU 사용량

예를들어 8개의 스레드를 만들어 작업한다 가정하면,

멀티스레드 언어는 8개 코어를 비슷하게 사용하고

싱글스레드 언어(파이썬)는 하나의 코어만 사용해서 1개의 코어의 사용량만 올라가고 아래와 같은 결과가 나온다.

 

1. 멀티쓰레드 환경

 

2. 싱글쓰레드 환경

운영체제는 여러 종류의 인터럽트를 걸며 하나의 프로세스를 위해 일하더라도

여러 코어를 사용하여 작업을 처리한다. CPU 사용량에서 c#(멀티쓰레드 환경)이 우위를 점하는데, 

c#으로 작성한 프로그램에서는 cpu사용량이 평균적으로 60~70이 나왔고

python으로 작성한 프로그램에서는 cpu사용량이 평균적으로 40~50이 나왔다.

(동일한 일을 하는데 CPU사용량이 높다는건 상대적으로 빠르게 일을 처리한다고 볼 수 있다.)

 

4) cpu사용량이 생각과 다르게 나온 이유

운영체제가 cpu는 하나의 프로세스를 위해 일을 하더라도 여러 코어로 왔다갔다 하며 일을 하게 된다.

파이썬은 GIL(Global Interpreter Lock)이 존재하며 동시에 하나의 코어에서만 일을 하는 언어이다.

 

이 말은 즉, 빠르게 여러개의 코어를 왔다갔다하는 방식으로 cpu를 사용한다.

스레드를 아무리 쪼개봐야 cpu를 동시에 사용하지 못한다.

(운영체제에는 여러가지 프로세스가 돌고있고 인터럽트들가 발생하고 커널의 레디큐에 있는 작업들은 잠시 CPU를 쓰고 timeout interrupt에 걸리는데 이때 운영체제의 스케줄링 방식이 하나의 코어에만 계속 요청을 하지는 않는다.)

 

c#, java등의 스레드는 여러개의 커널레벨 스레드를 사용하므로 운영체제가 여러개의 CPU에 스케줄링 한다.

이론상 8개의 코어에 동일한작업이 하나씩 할당 돼야 하지만 운영체제는 이미 많은 프로세스가 돌아가고있고 운영체제의 복잡한 스케줄링기법에 따라 스케줄링 되고 컨텍스트 스위칭이 일어날 것이다.(CPU의 6번과 8번 스레드는 상대적으로 놀고있다) 

 그래도 여러 CPU에 스케줄링하니 동시에 CPU를 사용할수 있어 CPU사용량도 높게나올뿐만 아니라 스레드는 공유하는 영역이 많아 캐시 데이터를 많이 사용할수 있어 그래프가 훨씬 평온한것을 확인할 수 있다.(아래측(python)은 그래프가 요동친다.)

'개발언어 > Python' 카테고리의 다른 글

[Python] 파이썬의 기본문법  (0) 2020.12.10
[Python] 파이썬 개념/ 설치  (0) 2020.12.10