왜 Multi Stream이 효과가 없는가 - 100-hours-a-week/5-yeosa-wiki GitHub Wiki
0. 참고자료
- https://vasusharma7.medium.com/single-gpu-inference-using-gpu-to-the-max-potential-8b2aebf5ca7b
- 해결하기 위한 노력(멀티 프로세스, 멀티 스트림, GIL 해제 등)
- 실제 해결한 방법(요청 배치 처리))
- https://github.com/pytorch/pytorch/issues/59692
- torch의 cuda stream이 직렬로 실행된다는 이슈
- https://github.com/pytorch/pytorch/issues/48279
- cuda 코드는 실제로 concurrent 처리가 되는데, torch의 stream API는 concurrent 실행이 되지 않는 이슈
1. 테스트 개요: GPU 멀티 스트림 도입
항목 | 내용 |
---|---|
목적 | CUDA stream을 활용하여 GPU 커널 병렬 실행을 유도하고, GPU 사용률 향상 |
환경 | FastAPI + PyTorch (CLIP ViT-B/32 모델), run_in_executor() 기반 처리 |
테스트 내용 | 요청마다 서로 다른 torch.cuda.Stream() 객체를 사용하여 병렬 추론 유도 |
관찰 결과 | GPU 사용률은 20% 이하로 낮게 유지, 여러 요청이 들어와도 병렬화 효과 없음 |
2. 기대와 다른 결과가 발생한 원인
run_in_executor()
기반 직렬성
a. GIL + - 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 연산이 겹치지 않음.