왜 Multi Stream이 효과가 없는가 - 100-hours-a-week/5-yeosa-wiki GitHub Wiki

0. 참고자료


1. 테스트 개요: GPU 멀티 스트림 도입

항목 내용
목적 CUDA stream을 활용하여 GPU 커널 병렬 실행을 유도하고, GPU 사용률 향상
환경 FastAPI + PyTorch (CLIP ViT-B/32 모델), run_in_executor() 기반 처리
테스트 내용 요청마다 서로 다른 torch.cuda.Stream() 객체를 사용하여 병렬 추론 유도
관찰 결과 GPU 사용률은 20% 이하로 낮게 유지, 여러 요청이 들어와도 병렬화 효과 없음

2. 기대와 다른 결과가 발생한 원인

a. GIL + run_in_executor() 기반 직렬성

  • Python GIL(Global Interpreter Lock)과 ThreadPoolExecutor는 요청을 완전 병렬로 실행하지 못함.
  • 각 요청은 FastAPI event loop에서 실행된 후 run_in_executor()로 CPU-bound 작업을 thread에서 수행함.
  • 이 구조에서는 stream에 task를 등록하는 시점이 **사실상 순차적(dispatch bottleneck)**임.

b. CLIP Inference의 커널 시간이 너무 짧음

  • CLIP 모델의 추론은 T4 기준 수십~수백 ms 수준의 연산.
  • 첫 stream에서 커널이 GPU에 올라가 실행되는 동안, 다음 stream이 커널을 dispatch하기도 전에 실행이 끝남.
  • 이로 인해 stream 간 실행이 겹치지 않고, 동시에 돌아가지 않음 → GPU는 마치 단일 stream처럼 작동.

c. GPU 커널 dispatch 타이밍이 병렬성 조건을 충족하지 않음

  • CUDA stream이 실제 병렬 실행을 하려면:
    • 커널 크기 큼
    • 커널 dispatch 타이밍 겹침
    • 연산 리소스 충분
  • CLIP Embedding은:
    • 커널이 작고 빠름
    • dispatch가 순차적
    • FastAPI 구조상 stream이 지연되며 올라감
  • 결국 단일 stream처럼 작동

3. 결론

  • 멀티 스트림 구조를 도입했지만, Python GIL 환경 + FastAPI의 run_in_executor() 구조에서는 stream마다 커널이 순차적으로 dispatch되었다.

    → CLIP의 추론 시간이 짧아 stream 간 GPU 연산이 겹치지 않음.