Interview/Python

Python GIL과 Thread

김 정출 2024. 10. 10. 23:55

Python GIL과 Thread

  • Python이 기본적으로 단일 프로세스 환경에서 동작하는 주요 이유 중 하나는 GIL(Global Interpreter Lock)이라는 메커니즘 때문입니다.
  • GIL은 Python 인터프리터가 한 번에 하나의 스레드만 실행되도록 제한하는 락(Lock)으로, 다중 스레드 환경에서 메모리 관리의 안전성을 보장하는 역할을 합니다.
  • GIL은 동시에 하나의 스레드만 Python 바이트코드를 실행할 수 있도록 하여, 멀티코어 CPU의 성능을 제대로 활용하지 못하는 상황을 유발합니다. 다만, GIL은 충돌을 방지하고, Python의 메모리 관리 시스템(CPython)의 안정성을 보장하기 위해 필요합니다.

1. GIL(Global Interpreter Lock)의 배경

  • Python은 기본적으로 C언어로 구현된 인터프리터를 사용하며, 메모리 관리와 관련된 부분이 참조 카운팅(Reference Counting) 방식으로 이루어집니다.
  • 참조 카운팅은 객체에 대한 참조가 추가되거나 제거될 때, 해당 객체의 참조 카운터를 증가시키거나 감소시키는 방식으로 메모리를 관리하는 기법입니다.
  • 다중 스레드 환경에서 여러 스레드가 동시에 동일한 객체의 참조 카운터를 변경할 경우 ****경쟁 상태(Race Condition)가 발생할 수 있습니다. 즉, 두 스레드가 동시에 객체의 참조 카운터를 변경하게 되면 메모리가 올바르게 해제되지 않거나, 잘못된 메모리 액세스가 일어날 수 있습니다.
  • 이를 방지하기 위해 GIL이 도입되었습니다. GIL은 Python 인터프리터가 한 번에 하나의 스레드만 Python 바이트코드를 실행하도록 보장함으로써, 참조 카운팅이나 메모리 할당 같은 작업이 안전하게 이루어지도록 합니다.

2. GIL의 영향

  1. 멀티스레드 성능 저하: GIL이 있기 때문에, Python에서는 멀티스레딩을 사용하더라도 CPU 바운드(CPU-intensive) 작업의 성능이 크게 향상되지 않습니다. 즉, 여러 스레드를 사용하더라도 CPU 집약적인 작업을 병렬로 처리하지 못하고, 실질적으로는 한 번에 하나의 스레드만 실행됩니다.
    • 예: 여러 스레드를 사용해 수학 계산 같은 CPU 집약적인 작업을 처리해도, GIL로 인해 스레드 간에 CPU 사용이 제한되기 때문에 속도가 크게 향상되지 않습니다.
  2. I/O 바운드 작업에서의 이점: 반면, I/O 바운드(I/O-intensive) 작업(네트워크 요청, 파일 읽기/쓰기 등)에서는 GIL이 크게 문제되지 않습니다. 이는 Python 스레드가 I/O 작업을 처리하는 동안 GIL을 해제하여 다른 스레드가 실행되도록 하기 때문입니다. 따라서 I/O 작업을 병렬적으로 처리하는 경우에는 멀티스레딩의 장점을 활용할 수 있습니다.
    • 예: 웹 서버나 파일 입출력 작업에서는 GIL이 큰 문제가 되지 않고, 여러 스레드가 동시에 실행될 수 있습니다.

3. Python이 단일 프로세스 환경인 이유 요약

  1. 메모리 관리의 안정성: GIL은 Python의 메모리 관리 시스템(참조 카운팅)을 안정적으로 유지하기 위해 필요합니다. 특히 다중 스레드 환경에서 메모리 액세스의 안전성을 보장하기 위한 중요한 메커니즘입니다.
  2. 초기 설계의 간결함: Python은 원래 설계가 단순성과 코드 가독성에 중점을 두고 있으며, 멀티스레드 환경을 복잡하게 관리하기보다는 GIL을 통해 단일 스레드 기반으로 안정성을 확보하는 방향을 선택했습니다.
  3. 멀티스레드 대신 멀티프로세스: Python에서는 GIL 때문에 멀티스레딩의 성능이 제한되지만, 이를 보완하기 위해 멀티프로세스 방식을 지원합니다. multiprocessing 모듈을 사용하면 여러 개의 프로세스를 병렬로 실행할 수 있으며, 각각의 프로세스는 독립적인 메모리 공간을 가지므로 GIL의 영향을 받지 않습니다.
    • 예: CPU 집약적인 작업을 병렬로 처리할 때는 멀티스레드 대신 멀티프로세스를 사용하는 것이 일반적입니다.

4. 단일 프로세스 환경의 해결 방법

  1. 멀티프로세싱 사용: GIL로 인한 문제를 해결하려면 multiprocessing 모듈을 사용하여 여러 프로세스를 병렬로 실행하는 방법이 있습니다.
  2. C로 작성된 확장 모듈 사용: NumPy나 SciPy와 같은 라이브러리들은 GIL을 해제하고 C 코드로 연산을 처리하여 GIL 문제를 우회합니다.
  3. PyPy 사용: PyPy는 GIL이 없는 파이썬 인터프리터로, 성능이 중요한 경우 대안이 될 수 있습니다.

5. 결론

Python이 단일 프로세스 환경에서 동작하는 주된 이유는 GIL 때문이며, 이는 메모리 관리의 안정성을 유지하기 위해 도입된 메커니즘입니다. GIL로 인해 CPU 집약적인 작업에서는 멀티스레딩의 이점이 제한되지만, I/O 바운드 작업에서는 문제가 되지 않으며, 멀티프로세싱을 통해 병렬 처리를 구현할 수 있습니다.