Ethan Hur's blog

Python 과 GIL, 그리고 Python 의 Concurrency

2018-02-14

Python 과 GIL, 그리고 Python 의 Concurrency

Python 에는 Global Interpreter Lock 이라는 것이 존재한다.

Global Interpreter Lock 은 Coarse-Grained Lock 의 끝판왕으로써 항상 특정 시점에 1개의 쓰레드만 동작하도록 하는 Lock 이다.

한마디로 One Huge Lock 이라고 생각하면 된다.

이 GIL 때문에 파이썬에서 C와 같은 multithreading 이 동작하지 않는다.

한 시점에 하나의 쓰레드만 실행되기 때문이다.

그러면 왜 Python 은 이러한 GIL 을 도입하였을까?

GIL 도입 이유

  1. 파이썬이 만들어질 당시에는 Multi-processor 가 보편화되지 않았음

  2. GIL 을 도입하므로써 인터프리터의 구현, GC의 구현이 단순화됨

  3. C extension 의 구현이 쉬워짐

그러면 GIL은 지금은 나쁜가?

이 질문도 생각해 볼 여지가 있다. 프로그램은 보통 I/O 가 많은 프로그램과 CPU intensive 한 프로그램으로 구분할 수 있다.

I/O bound

비동기 호출로 I/O 가 걸리는 순간, GIL 이 풀리면서 다른 Thread 가 실행되게 된다.

따라서 I/O 가 많은 프로그램에서는 GIL 을 쓰는 단점을 그렇게 느끼진 못한다. 오히려 장점이 더 부각되는 느낌이다. ( I/O bound 관점에서 봤을 땐 Javascript 의 이벤트 루프랑 비슷해 보인다.)

CPU intensive

CPU 를 많이 잡아먹는 연산 프로그램의 경우는 GIL 이 문제가 된다.

한 쓰레드에서 연산을 하는 동안 다른 쓰레드는 놀고 있기 때문이다.

위와 같은 경우의 해결책은 2가지가 있다.

C extension 사용

C extension 의 경우 GIL 이 거는 Lock 의 범위 밖에 있으므로 연산을 위해 C extension 으로 요청을 보내는 순간, 이를 I/O 와 똑같이 판단하여 Lock 이 풀린다.

그리고 많은 연산이 필요한데 굳이 C extension 을 사용하지 않을 이유는 없다. (Glue 언어로써의 Python은 너무 훌륭하지 않은가)

Multiprocess 사용

쓰레드를 여러 개 띄우는 것이 아니라 프로세스를 여러개 띄우게 되면 이러한 문제는 해결된다.

Process 는 메모리 입장에서도 독립적인 단위이기 때문에 Lock 이 따로 걸려서, Process 마다 병렬처리 할 수 있게 된다.

또한 파이썬에서는 multiprocessing 이라는 모듈도 기본 모듈로 제공한다. 파이썬으로 분산 관련 구현을 하기 위해선 필수적으로 사용해야 할 듯 하다.


Python 에서의 Concurrent 프로그래밍은 C나 Java와 같은 Compile 언어의 그것과는 다른 방향으로 접근해야 할 듯 하다.

실제로 Python 에서 빡센 Concurrent 프로그램을 짠 적은 없지만 그 때 참고하기 위해 기록한다.