파이썬의 표준 라이브러리는 멀티스레딩을 위해 threading 모듈을 제공합니다. 스레드는 하나의 프로세스 내에서 여러 작업을 동시에 수행할 수 있게 해줍니다. 그러나 파이썬의 표준 구현(CPython)에서는 **GIL(전역 인터프리터 잠금)**이라는 메커니즘이 존재하여, 오직 하나의 스레드만이 파이썬 바이트코드를 동시에 실행할 수 있습니다.
이는 CPython에서 멀티스레딩이 CPU 수준에서 파이썬 코드를 실행할 때 실제 병렬성을 달성할 수 없음을 의미합니다. 병렬성은 대기(I/O-bound)와 관련된 작업에만 유용합니다. CPU-bound 작업의 경우 multiprocessing 모듈을 사용하는 것이 좋으며, 이는 여러 프로세스를 시작하여 GIL을 우회합니다.
예:
import threading def worker(): print('시작') # 무거운 계산 print('끝') threads = [threading.Thread(target=worker) for _ in range(5)] for t in threads: t.start() for t in threads: t.join()
집약적인 계산을 위한 병렬성을 원할 경우 multiprocessing를 사용하십시오:
from multiprocessing import Pool def square(x): return x*x with Pool(4) as p: print(p.map(square, [1, 2, 3, 4]))
파이썬의 멀티스레딩이 compute-heavy 작업의 실행 속도를 높일 수 있을까요?
답변: 아닙니다. CPython의 GIL 때문에 스레드는 CPU-bound 작업에서 성능 향상을 제공하지 않습니다. 이러한 작업에는 multiprocessing 또는 GIL이 없는 대체 인터프리터 구현(Jython, IronPython 등)을 사용하세요.
이야기
대용량 데이터 처리 프로젝트에서 팀은 스레드를 사용하여 계산 속도를 높이려 했습니다. 속도가 높아지기는커녕, GIL 때문에 스레드가 병렬로 작업할 수 없었고 작업 시간이 늘어났습니다. 이후
multiprocessing으로 전환하자 문제가 해결되었습니다.
이야기
한 개발자는 대용량 파일을 동시에 다운로드하고 여러 스레드에서 처리하려 했지만, 공유 변수의 안전하지 않은 사용으로 인해 종종 "deadlock"에 걸렸습니다.
이야기
백엔드 서버에서 스레드 풀에서 무거운 요청 처리가 구현되었습니다. 부하가 증가하자 서버가 "멈추기" 시작했는데, 대부분의 시간 스레드가 GIL로 인해 파이썬 코드를 실행 대기 중이었던 것으로 나타났습니다. 요청은 집중적인 I/O와 관련이 없었음에도 불구하고 말이죠.