2011년 11월 13일 일요일

파이썬 스레드 threading GIL

파이썬에서는 특이한 GIL이라는게 있습니다.

GIL이란 무엇이냐 하면 Global Interpreter Lock의 약자로 하나의 파이썬 인터프리터에서는 하나의 작업만 실행이 가능한 것입니다.  음 왜냐하면, 하나의 인터프리터가 실행이 될때, global 변수로 제어를 하기때문에, 여러 스레드가 동시에 건드릴 경우, 뒤죽박죽이 되기에, 한번에 하나의 스레드만이 인터프리터 내부 global 변수에 접근가능하도록 해놓은것입니다.

이것이 무슨일을 벌이느냐 하면, 멀티 스레드 프로그램을 짰을 경우 다른 스레드로 들어가기전에 락을 걸어놓고 움직입니다. 그래서,멀티스레드라 할지라도 결국에는
한번에 하나의 스레드가 time sharing하는 형태로 실행이 됩니다.

그래서 결과적으로  멀티코어 CPU라고 하더라도, 스레드를 사용할 경우 그다지 효과가 없고, 오히려 실행시간이 늘어나게 됩니다. 멀티스레드 모듈이 존재하긴 하는데,
이것이 그다지 효과가 없습니다. 그냥 시분할로 돌리는것과 성능이 비슷합니다.
이것이 효과를 보는 경우는 I/O같이  시간을 많이 잡아먹는 경우에는 효과가 있습니다.
I/O 타임에는 CPU가 놀고 있기때문에, 이때는 효과적이지만,
하이퍼스레딩이나, SMT같이 CPU 코어한개안에서 여럿의 프로세스들 돌리는 형태로는
효과를 많이 보지 못합니다.

예를 들면 1부터 200까지 더하는 프로그램을 짠다고 할 경우

1. 하나의 스레드는 처음부터 끝까지 진행

2. 두개의 스레드로 나눠서 하나는 1부터 100까지 더하게 하고,
    다른 하나는 101부터 200까지 더하게 해서 합하는 경우

1번이 무조건 빠르게 됩니다.

2번의 경우 multithread를 쓴다면 효과가 있어야 되는데, 이 GIL때문에 하나의 cpu만을 가지고 진행하기때문에 중간에 Lock을 걸고 풀고하는 비용이 추가가 되어서, 2번이 1번보다 항상 느리게 됩니다.

그래서 이에 대한 해결 방법으로는 multiprocess를 쓰는 방법입니다.

즉, 하나의 interpreter를 쓰는게 아니라 여럿의 프로세서를 구동시키는 것이죠,

이 경우에는 프로세스 관리는 python에서 하는 것이 아니라 os에서 하는 것이기 때문에,
OS에서 적절하게 프로세스를 코어별로 할당을 하게 해서, 전체적으로 스피드를 올려주게 됩니다.

그럼에도 불구하고, 사실 멀티프로세서도 좋은 모델이긴하지만,
아쉬움이 많이 있습니다.

멀티프로세서와 하이퍼 스레딩같이 풀파워로 돌리기는 어렵고,
멀티프로세서를 극대화시키고,
적절하게 I/O bound 한 부분과 CPU bound한 부분을 나누는 것이 중요합니다.

또, 다른 방법은 GIL이 없는 구현, 예를들면, Jython 이나 IronPython을 이용하는 방법도 있긴합니다.  https://wiki.python.org/moin/GlobalInterpreterLock

하지만, 일반적인 job을 하는 경우는 사실 이 상황을 맞닥드리긴 힘듭니다.
파이썬같은 경우는 주로 prototype 에서 가장좋은 효율을 보이기때문에,
이렇게 GIL에 장벽에 가로막히는 일까지 가는 경우가 그렇게 잘 발생하지는 않습니다.

CPU의 모든 성능을 끌어내는 경우는 보통 어떤 일이 완료된다음에 최적화수순을 밟는 경우라서,
이때는 bottleneck을 C로짜는 경우도 있고,
중요한 시스템은 C나 자바로 돌리는게 아직까지는 현실이기때문입니다.

이것 자체는 사실 좋은 주제이기때문에, GIL을 무력화시키려는 시도는 여럿있어 왔습니다만

여러가지 문제가 있어서, 아직까지는 GIL을 유지하는 것으로 가고 있습니다.













댓글 없음:

댓글 쓰기