[AI] 단일 스레드 환경인 파이썬에서, 왜 스레드 수 제한이 유효했을까? - 100-hours-a-week/5-yeosa-wiki GitHub Wiki

1. 이 생각이 들게 된 계기

  • 기본적으로 Python은 GIL로 인해 단일 스레드 환경으로 작동하는 것으로 알고 있었음.

  • 그런데 모델 학습 중 torch.set_num_threads를 설정했더니,

    실제로 CPU 사용률이 줄어드는 현상을 관찰함.

  • 만약 Python이 진짜 단일 스레드로만 동작했다면 스레드 수 설정이 의미가 없었을 것.

  • 그래서 "PyTorch는 내부적으로 다중 스레드로 동작하고 있는 것 아닐까?"라는 의문이 생김.


2. GIL (Global Interpreter Lock)이란?

  • GIL은 CPython 인터프리터 내부에 존재하는 락.

  • 한 순간에 하나의 스레드만 Python 바이트코드를 실행할 수 있도록 강제.

  • 이로 인해 Python은 멀티스레드 환경에서도 CPU 바운드 작업에서 진정한 병렬성 확보가 어려움.

  • GIL이 네트워크 바운드와 CPU 바운드에 미치는 차이

    • 네트워크 바운드 작업: I/O 대기 중 다른 스레드로 전환이 가능.
    • CPU 바운드 작업: 한 스레드가 CPU를 독점하여 GIL이 병목이 됨.
    구분 네트워크 바운드 작업 CPU 바운드 작업
    CPU 사용 거의 없음 (대기 상태) 지속적인 사용
    스레드 전환 대기 중 자연스럽게 전환 전환 어려움 (GIL 독점)
    멀티스레딩 효과 적음
    예시 웹 요청, 파일 다운로드 수치 계산, 데이터 암호화

3. PyTorch는 어떻게 작동하는가?

  • PyTorch는 Python에서 명령만 전달하고, 실제 연산은 **C++ 네이티브 코드(ATen, THC 등)**가 수행.

  • Python 레벨에서는 CPython GIL이 적용되지만, C++ 연산 중에는 GIL이 해제됨.

  • C++ 코드 실행 동안에는 Python 인터프리터 제약 없이 멀티코어 병렬 연산이 가능.

  • 따라서 torch.set_num_threads를 설정하면 내부 C++ 스레드 수를 제어할 수 있고, CPU 사용량에도 직접적인 영향을 준다.

  • 흐름 요약

    Python 코드
      ↓ (명령 전달)
    PyTorch Python Bindings
      ↓ (C++ 함수 호출)
    ATen, TH 라이브러리 (C++ 연산 엔진)
      ↓
    CPU/GPU에서 실제 연산
      ↓
    Python 오브젝트로 결과 반환
    

4. torch.set_num_threads가 CPU 사용량을 줄이는 이유

  • torch.set_num_threads(n)은 PyTorch 내부 C++ 연산 시 사용할 스레드 수를 설정.
  • 내부적으로 OpenMP, pthreads 같은 라이브러리를 통해 병렬 연산을 수행.
  • 스레드 수를 줄이면 병렬 처리 양이 줄어들고, 결과적으로 CPU 사용량도 감소.

5. 최종 요약

  • GIL은 Python 코드 실행을 한 번에 하나의 스레드로 제한.
  • PyTorch는 Python을 통해 명령을 전달하지만, 실제 연산은 GIL이 해제된 C++ 코드가 수행.
  • C++ 코드에서는 멀티스레드, 멀티코어 병렬 처리가 가능.
  • torch.set_num_threads를 통해 내부 병렬 스레드 수를 제어할 수 있으며, 이로써 CPU 사용량을 효과적으로 관리할 수 있다.