fos-blog/study
01 / 홈02 / 카테고리03 / 시리즈
01 / 홈02 / 카테고리03 / 시리즈

카테고리

  • AI 페이지로 이동
    • RAG 페이지로 이동
    • langgraph 페이지로 이동
    • agents.md
    • BMAD Method — AI 에이전트로 애자일 개발하는 방법론
    • Claude Code의 Skill 시스템 - 개발자를 위한 AI 자동화의 새로운 차원
    • Claude Code를 5주 더 쓴 결과 — 스킬·CLAUDE.md를 키워가는 방식
    • Claude Code를 11일 동안 쓴 결과 — 데이터로 본 나의 사용 패턴
    • Claude Code 멀티 에이전트 — Teams
    • AI 에이전트와 디자인의 새 컨벤션 — DESIGN.md, Google Stitch, Claude Design
    • Docling — IBM Research 의 문서 파싱 toolkit 상세 정리
    • 하네스 엔지니어링 실전 — 4인 에이전트 팀으로 코딩 파이프라인 구축하기
    • 하네스 엔지니어링 — 오래 실행되는 AI 에이전트를 위한 설계
    • 멀티모달 LLM (Multimodal Large Language Model)
    • AI 에이전트와 함께 MVP 만들기 — dooray-cli 사례
  • ai 페이지로 이동
    • agent 페이지로 이동
  • algorithm 페이지로 이동
    • live-coding 페이지로 이동
    • 분산 계산을 위한 알고리즘
  • apartment 페이지로 이동
    • 구리 럭키아파트 24평 인테리어 레퍼런스 모음
  • architecture 페이지로 이동
    • [초안] 시니어 백엔드를 위한 API 설계 실전 스터디 팩 — REST · 멱등성 · 페이지네이션 · 버전 전략
    • [초안] API Versioning과 Backward Compatibility: 시니어 백엔드 관점 정리
    • 캐시 설계 전략 총정리
    • [초안] CJ푸드빌 디지털 채널 면접: 슬롯 도메인 경험을 커머스 도메인 설계 능력으로 번역하기
    • [초안] 커머스 Spring 서비스에 Clean/Hexagonal Architecture를 실용적으로 적용하기
    • [초안] 커머스 도메인 모델링: 주문·재고·노출의 세 축을 분리해서 설계하기
    • 커머스 주문 상태와 데이터 정합성 기본기 — CJ푸드빌 면접 대비
    • [초안] 쿠폰/프로모션 동시성과 정합성 기본기 — 선착순·중복 사용 방지·발급/사용/복구
    • [초안] DDD와 도메인 모델링: 시니어 백엔드 관점의 전술/전략 패턴 실전 가이드
    • [초안] Decorator & Chain of Responsibility — 행동을 체인으로 조립하는 두 가지 방식
    • 디자인 패턴
    • [초안] 분산 아키텍처 완전 정복: Java 백엔드 시니어 인터뷰 대비 실전 가이드
    • [초안] 분산 트랜잭션과 Outbox 패턴 — 왜 2PC를 피하고 어떻게 대신할 것인가
    • 분산 트랜잭션
    • [초안] e-Commerce 주문·결제 도메인 모델링: 상태머신, 멱등성, Outbox/Saga 실전 정리
    • [초안] F&B 쿠폰·프로모션·멤버십·포인트 설계
    • [초안] F&B · e-Commerce 디지털 채널 도메인 한 장 정리 — CJ푸드빌 디지털 채널 백엔드 면접 대비
    • [초안] F&B 주문/매장/픽업 상태머신 설계 — CJ푸드빌 디지털 채널 백엔드 관점
    • [초안] F&B 이커머스 결제·환불·정산 운영 가이드
    • [초안] Hexagonal / Clean Architecture를 Spring 백엔드에 적용하기
    • [초안] 대규모 커머스 트래픽 처리 패턴 — 1,600만 고객과 올영세일을 버티는 설계
    • [초안] 레거시 JSP/jQuery 화면과 신규 API가 공존하는 백엔드 운영 전략
    • [초안] MSA 서비스 간 통신: Redis [Cache-Aside](../database/redis/cache-aside.md) × Kafka 이벤트 하이브리드 설계
    • [초안] Observability 입문: 시니어 백엔드가 장애를 탐지하고 대응하는 방식
    • [초안] Outbox / Inbox Pattern 심화 — 분산 메시징의 정합성 문제를 DB 트랜잭션으로 풀어내기
    • [초안] 결제 도메인 멱등성과 트랜잭션 재시도 기본기
    • [초안] 시니어 백엔드를 위한 Resilience 패턴 실전 가이드 — Timeout, Retry, Circuit Breaker, Bulkhead, Backpressure
    • [초안] REST API 버저닝과 모바일 앱 하위 호환성 — CJ푸드빌 디지털 채널 백엔드 관점
    • [초안] Spring Batch vs Event-Driven — 같은 비동기처럼 보이지만 전혀 다른 두 패러다임
    • [초안] Strategy Pattern — 분기문을 없애는 설계, 시니어 백엔드 인터뷰 핵심 패턴
    • [초안] 시니어 백엔드를 위한 시스템 설계 입문 스터디 팩
    • [초안] 템플릿 메서드 패턴 - 백엔드 처리 골격을 강제하는 가장 오래되고 가장 위험한 패턴
    • [초안] 대규모 트래픽 중 무중단 마이그레이션 — Feature Flag + Shadow Mode 실전
  • database 페이지로 이동
    • mysql 페이지로 이동
    • opensearch 페이지로 이동
    • redis 페이지로 이동
    • 김영한의-실전-데이터베이스-설계 페이지로 이동
    • [초안] DB Connection Pool Saturation과 Thread Pool 격리
    • 커넥션 풀 크기는 얼마나 조정해야 할까?
    • 인덱스 - DB 성능 최적화의 핵심
    • [초안] JPA N+1과 커머스 조회 모델: 주문/메뉴/쿠폰 도메인에서 살아남기
    • [초안] MyBatis 기본기 — XML Mapper, resultMap, 동적 SQL, 운영 패턴 정리
    • [초안] MyBatis와 JPA/Hibernate 트레이드오프 — 레거시 백엔드를 다루는 시니어 관점
    • 역정규화 (Denormalization)
    • 데이터 베이스 정규화
  • devops 페이지로 이동
    • docker 페이지로 이동
    • k8s 페이지로 이동
    • k8s-in-action 페이지로 이동
    • observability 페이지로 이동
    • [초안] 커머스/F&B 채널 장애 첫 5분과 관측성 기본기
    • Envoy Proxy
    • [초안] F&B / e-Commerce 운영 장애 대응과 모니터링 — 백엔드 관점 정리
    • Graceful Shutdown
    • [초안] 시니어 백엔드를 위한 SLO와 Error Budget 기반 장애 대응
  • finance 페이지로 이동
    • industry-cycle 페이지로 이동
    • investing 페이지로 이동
  • http 페이지로 이동
    • HTTP Connection Pool
  • interview 페이지로 이동
    • [초안] AI 서비스 팀 경험 기반 시니어 백엔드 면접 질문 뱅크 — Spring Batch RAG / gRPC graceful shutdown / 전략 패턴 / 12일 AI 웹툰 MVP
    • [초안] 커머스/F&B 면접 답변집 — 슬롯 도메인 경험을 주문·결제·쿠폰·매장 설계로 매핑하기
    • [초안] F&B / e-Commerce 운영 모니터링과 장애 대응 인터뷰 정리
    • Observability — 면접 답변 프레임
    • [초안] 시니어 Java 백엔드 면접 마스터 플레이북 — 김병태
    • [초안] NSC 슬롯팀 경험 기반 질문 은행 — 도메인 모델링·동시성·성능·AI 협업
  • java 페이지로 이동
    • concurrency 페이지로 이동
    • jdbc 페이지로 이동
    • opentelemetry 페이지로 이동
    • spring 페이지로 이동
    • spring-batch 페이지로 이동
    • 더_자바_코드를_조작하는_다양한_방법 페이지로 이동
    • [초안] Java 동시성 락 정리 — 커머스 메뉴/프로모션 정책 캐시 갱신 관점
    • [초안] JVM 튜닝 실전: 메모리 구조부터 Virtual Threads, GC 튜닝, 프로파일링까지
    • Java의 로깅 환경
    • MDC (Mapped Diagnostic Context)
    • Java StampedLock — 읽기 폭주에도 쓰기가 밀리지 않는 락
    • Virtual Thread와 Project Loom
  • javascript 페이지로 이동
    • typescript 페이지로 이동
    • AbortController
    • Async Iterator와 제너레이터
    • CommonJS와 ECMAScript Modules
    • 제너레이터(Generator)
    • Http Client
    • Node 백엔드 운영 패턴 — Streams 백프레셔, pipe/pipeline, 멱등성 vs 분산 락
    • Node.js
    • npm vs pnpm — 어떤 기준으로 선택했나
    • `setImmediate()`
  • kafka 페이지로 이동
    • [초안] Kafka 기본 개념 — 토픽, 파티션, 오프셋, 복제
    • Kafka를 사용하여 **데이터 정합성**은 어떻게 유지해야 할까?
    • [초안] Kafka 실전 설계: 파티션 전략, 컨슈머 그룹, 전달 보장, 재시도, 순서 보장 트레이드오프
    • 메시지 전송 신뢰성
  • linux 페이지로 이동
    • fsync — 리눅스 파일 동기화 시스템 콜
    • tmux — Terminal Multiplexer
  • network 페이지로 이동
    • L2(스위치)와 L3(라우터)의 역할 차이
    • L4와 VIP(Virtual IP Address)
    • IP Subnet
  • python 페이지로 이동
    • Python async/await — CompletableFuture·Reactor 와 다른 점, 그리고 blocking I/O 함정
    • Python 의존성 관리 — Java Maven/Gradle 사용자가 만나는 첫 충격
    • FastAPI 기초 — Spring Boot 사용자가 빠르게 익히는 법
    • GPU·CUDA·MPS 기초 — 자바 백엔드 개발자가 처음 만나는 그림
    • Multi-process GPU 워크로드 — 자바 ThreadPool 사용자가 만나는 모델 차이
    • Java 개발자를 위한 Python 심화 — OOP·데코레이터·컨텍스트 매니저
    • PyTorch 기초 — 텐서, 디바이스, 그리고 모델 로딩이 무거운 이유
    • Java 개발자를 위한 Python 문법 핵심
    • ML 서비스 성능 분석 워크플로 — 자바 백엔드 트러블슈팅과 다른 점
    • OCR 동작 원리 — Layout · Text · Post-process 3단계
    • Python 서버의 RSS 가 안 줄어드는 이유 — gc.collect 의 한계와 malloc_trim
  • rabbitmq 페이지로 이동
    • [초안] RabbitMQ Basics — 실전 백엔드 관점에서 정리하는 메시지 브로커 기본기
    • [초안] RabbitMQ vs Kafka — 백엔드 메시징 선택 기준과 실전 운영 관점
  • security 페이지로 이동
    • [초안] 시니어 백엔드를 위한 보안 / 인증 스터디 팩 — Spring Security, JWT, OAuth2, OWASP Top 10
    • [초안] Spring Security 6.x OAuth2 + JWT 상용 인증 설계 — Grant 선택, Resource Server, Refresh Rotation, 로그아웃
  • task 페이지로 이동
    • ai-service-team 페이지로 이동
    • nsc-slot 페이지로 이동
    • sb-dev-team 페이지로 이동
    • the-future-company 페이지로 이동
  • testing 페이지로 이동
    • [초안] 시니어 Java 백엔드를 위한 테스트 전략 완전 정리 — 피라미드부터 TestContainers, 마이크로벤치, Contract까지
  • travel 페이지로 이동
    • 오사카 3박 4일 일정표: 우메다 쇼핑, USJ, 난바·도톤보리, 오사카성
  • web 페이지로 이동
    • [초안] HTTP / Cookie / Session / Token 인증 기본기 — 레거시 JSP와 모바일 API가 공존하는 백엔드 관점
FOS-BLOG · FOOTERall systems normal·v0.1 · 2026.04.27·seoul, kr
Ffos-blog/study

개발 학습 기록을 정리하는 블로그입니다. 공부하면서 기록하고, 기록하면서 다시 배웁니다.

visitors
01site
  • Home↗
  • Posts↗
  • Categories↗
  • About↗
02policy
  • 소개/about
  • 개인정보처리방침/privacy
  • 연락처/contact
03categories
  • AI↗
  • Algorithm↗
  • DB↗
  • DevOps↗
  • Java/Spring↗
  • JS/TS↗
  • React↗
  • Next.js↗
  • System↗
04connect
  • GitHub@jon890↗
  • Source repositoryjon890/fos-study↗
  • RSS feed/rss.xml↗
  • Newsletter매주 1 회 · 한 편의 글→
© 2026 FOS Study. All posts MIT-licensed.
built with·Next.js·Tailwind v4·Geist·Pretendard·oklch
fos-blog/python/Multi-process GPU 워크로드 —…
system

Multi-process GPU 워크로드 — 자바 ThreadPool 사용자가 만나는 모델 차이

자바 백엔드에서 ThreadPoolExecutor 는 거의 만능이었다. CPU bound 든 I/O bound 든 스레드 풀 크기만 잘 잡으면 동시성을 챙길 수 있었다. JVM 안에서 메모리를 공유하니 작업 간 데이터 전달도 가볍다. Python ML 서비스는 그림이 다르다. ThreadPoolExecutor 가 있지만 CPU/GPU 작업에서는 거의 안 쓰...

2026.05.19·7 min read·18 views

자바 백엔드에서 ThreadPoolExecutor 는 거의 만능이었다. CPU bound 든 I/O bound 든 스레드 풀 크기만 잘 잡으면 동시성을 챙길 수 있었다. JVM 안에서 메모리를 공유하니 작업 간 데이터 전달도 가볍다.

Python ML 서비스는 그림이 다르다. ThreadPoolExecutor 가 있지만 CPU/GPU 작업에서는 거의 안 쓰고, 대신 ProcessPoolExecutor (실제 OS 프로세스 풀) 를 쓴다. 우리 프로젝트도 KR 워커 2개 + JA 워커 1개를 모두 별도 프로세스로 띄운다. 자바 시각에서는 "왜 굳이 무거운 프로세스를?" 라는 의문이 자연스럽게 생긴다.

이 글은 그 의문에 답하고, multi-process GPU 워크로드의 핵심 패턴 4개를 자바 ThreadPool 과 비교해 정리한다.

  • worker 라이프사이클
  • MAX_TASKS_PER_WORKER
  • NVIDIA MPS
  • worker death monitor

왜 thread 가 아니라 process 인가 — GIL 의 결정

이전 async/await 글 에서 짚었듯 CPython 은 GIL (Global Interpreter Lock) 로 인터프리터에 큰 락을 박았다. 한 프로세스 안에서는 한 번에 하나의 스레드만 Python 바이트코드를 실행한다.

자바에서 Runtime.getRuntime().availableProcessors() 만큼 스레드를 띄워 CPU 작업을 병렬화하는 패턴은 Python 에서는 거의 동작하지 않는다. CPU 시간이 단일 스레드로 직렬화되기 때문.

GPU 작업도 비슷한 영향을 받는다. PyTorch 가 CUDA kernel 을 호출하는 잠깐 동안 GIL 을 놓지만, 그 외 파이썬 코드 (전처리·후처리·dispatch) 가 직렬화된다. 모델 추론 자체가 빠르더라도 주변 코드가 병목이 되면 throughput 이 올라가지 않는다.

해결책은 프로세스 단위 격리. 프로세스마다 독립 인터프리터·독립 GIL 을 가지므로 진짜 병렬 실행이 된다.

비교자바 ThreadPoolPython ProcessPool
단위OS 스레드OS 프로세스
메모리JVM 안에서 공유격리 (IPC 필요)
생성 비용가벼움 (수십 μs)무거움 (Python 인터프리터 + 모델 로드, 수 초)
데이터 전달객체 참조 직접pickle 직렬화 + IPC
GIL 영향없음없음 (프로세스 분리)
OOM 영향 범위JVM 전체해당 프로세스만
모니터링 단위jstackps, nvidia-smi

가장 큰 차이는 메모리 격리와 생성 비용. 자바라면 1ms 만에 새 스레드를 만들지만, Python ProcessPool 의 worker spawn 은 우리 실측으로 5.74초 (MAX_TASKS_PER_WORKER 도달 시 매번). PyTorch 모델 로딩 글 에서 분해한 다섯 단계가 매 spawn 마다 반복된다.

ProcessPoolExecutor 의 동작

자바의 ExecutorService 자리에 concurrent.futures.ProcessPoolExecutor 가 들어간다.

python
from concurrent.futures import ProcessPoolExecutor
 
def init_worker():
    # 워커 프로세스가 시작될 때 한 번만 실행
    global converter
    converter = build_converter()
 
def process_document(path: str) -> str:
    return converter.convert(path)
 
executor = ProcessPoolExecutor(
    max_workers=2,
    initializer=init_worker,
    max_tasks_per_child=50,
)
 
future = executor.submit(process_document, "/tmp/file.pdf")
result = future.result(timeout=1200)

initializer 는 자바 ThreadFactory 에서 beforeExecute 자리. 각 워커 프로세스가 시작될 때 한 번 호출되어 무거운 모델을 미리 로드한다. 우리 코드의 init_worker_process 함수가 이 자리에서 PaddleOCR + Docling converter 를 워커마다 캐싱한다.

max_tasks_per_child 는 자바에 없는 옵션. 워커 한 명이 N 개 task 를 처리하면 자동으로 죽고 새 워커가 spawn 된다. 메모리 누수 방어용으로 도입된 패턴인데, 우리 분석에서는 이 값이 너무 작게 (3) 설정되어 throughput 손해가 큰 것으로 드러났다.

워커 라이프사이클

자바 ThreadPool 의 스레드는 보통 영원히 살아 있다. 작업 큐에서 작업을 꺼내 실행하고 다음 작업을 기다리는 것을 반복.

Python ProcessPool 의 워커는 라이프사이클이 더 명시적이다.

  1. Spawn — os.fork() 또는 spawn 방식으로 새 프로세스 생성 (Linux 기본 fork, macOS·Windows 기본 spawn)
  2. Initialize — initializer 호출, 모델 로딩, GPU 컨텍스트 생성. 5-30초 소요.
  3. Process tasks — 작업 큐에서 task pickle 을 받아 실행, 결과 pickle 로 반환
  4. Recycle(선택) — max_tasks_per_child 도달 시 종료, 새 워커가 자리에 spawn
  5. Death — 예외·OOM·외부 시그널로 비정상 종료

자바와 결정적으로 다른 점은 3번에서 4번 사이의 비용. 자바 스레드는 그냥 다음 작업을 받지만, Python 프로세스는 종료 후 새 프로세스가 모델을 다시 로드한다. 워밍업 비용 5.74초가 이 사이클의 핵심 부담이 된다.

MAX_TASKS_PER_WORKER 의 트레이드오프

자바 ThreadPool 에는 거의 없는 개념이지만 Python 에서는 표준 패턴이 됐다. 이유는 두 가지.

메모리 누수 방어: PyTorch / PaddleOCR 같은 native 라이브러리가 가끔 메모리를 명확히 회수하지 않는 케이스가 있다. JVM GC 처럼 자동 회수가 잘 되는 환경이 아니라서, 일정 작업마다 프로세스를 죽이고 다시 만들어 메모리를 초기화하는 게 안전.

predictable shutdown: 자바 GC tuning 처럼 메모리 추세를 예측하기 어려운 워크로드에서 "N 건마다 무조건 reset" 이라는 단순 규칙이 운영 안정성을 준다.

비용은 명확하다. 매번의 워밍업 시간이 누적된다. 우리 운영의 MAX_TASKS=3 은 12시간 동안 1,565회 워밍업 = 약 150분의 누적 다운타임을 만든다. 적정값을 찾으려면 메모리 추세를 실측한 뒤 점진적 상향을 권한다 (우리 케이스는 50 수준이 안전한 것으로 판단).

자바의 Tomcat 가 worker 스레드를 자동 재활용하지 않는 것과 대비된다. 자바는 그 자리에 heap dump + GC tuning 으로 대응. Python ML 서비스는 더 외과적인 "주기적 reset" 방식.

NVIDIA MPS — multi-process GPU 효율화

GPU·CUDA 글 에서 NVIDIA MPS 를 짚었다. multi-process GPU 워크로드의 핵심 최적화.

기본 모드에서는 각 프로세스가 GPU 에 접근할 때 자체 CUDA context 를 만든다. 우리 워커 3개라면 CUDA context 3개 × 300-600MB = ~1.5GB VRAM 이 그냥 컨텍스트로 소비. T4 15GB 중에 큰 비중.

NVIDIA MPS daemon 을 띄우면 여러 프로세스가 같은 컨텍스트를 공유한다. VRAM 절약 + 컨텍스트 전환 비용 감소. 우리 운영은 현재 MPS=OFF 인데, multi-process 워커 수를 늘릴 때 MPS 를 켜는 게 ROI 있는 방향.

자바에는 비유할 게 없는 영역. JVM 자체가 프로세스 격리를 받지 않고 OS 의 GPU 직접 접근도 거의 없기 때문.

Round-Robin GPU 스케줄링

multi-GPU 환경에서는 작업을 어느 GPU 에 보낼지 결정해야 한다. 우리 프로젝트 코드는 KR / JA / Priority 풀별로 Round-Robin index 를 락으로 보호하면서 GPU 를 순회한다.

python
_kr_gpu_round_robin_idx = 0
_kr_gpu_round_robin_lock = threading.Lock()
 
def get_kr_executor() -> ProcessPoolExecutor:
    global _kr_gpu_round_robin_idx
    with _kr_gpu_round_robin_lock:
        idx = _kr_gpu_round_robin_idx % len(available_gpus)
        _kr_gpu_round_robin_idx += 1
    return _kr_executors[idx]

자바 AtomicInteger 의 incrementAndGet() 자리. 단 single GPU 환경에서는 idx % 1 = 0 으로 항상 같은 결과라 락만 잡고 효과가 없다. 우리 분석에서 이슈로 잡힌 부분. multi-GPU 클러스터로 확장될 가능성이 있는 코드라 일반화는 합리적이지만, 단일 GPU 케이스의 단락 처리를 추가하는 게 좋다.

Worker death monitor — 자바엔 없는 패턴

자바 ThreadPool 의 스레드가 예외로 죽으면 풀이 새 스레드를 spawn 한다. Python ProcessPool 도 비슷하지만, 모니터링이 더 명시적이다.

우리 코드의 worker_death_monitor 는 별도 thread 가 1초 간격으로 executor 의 워커 상태를 확인한다. 죽은 워커가 발견되면 즉시 새 worker 를 spawn 한다.

python
def worker_death_monitor():
    while True:
        for executor in [_kr_executor, _ja_executor]:
            if has_dead_worker(executor):
                respawn(executor)
        time.sleep(1)

자바라면 Thread.setUncaughtExceptionHandler + 풀 내장 동작으로 해결되는 일을, Python 에서는 별도 watchdog 스레드로 풀어야 한다. 프로세스 간 통신·죽음 감지가 일반적으로 더 깨지기 쉬워서다.

restart-all-at-once 패턴의 함정

우리 분석에서 가장 큰 운영 이슈로 잡힌 것이 restart_all_executors_if_needed 패턴. RAM threshold 도달 또는 수동 /restart 호출 시 KR/JA/Priority 풀을 동시에 teardown 한 뒤 _is_restarting=True 동안 모든 incoming 요청을 503 으로 거부한다.

실측 결과 12시간 동안 503 응답이 225,803회. 거부율 96.7%. 같은 시점에 다른 풀이 살아 있도록 staggered restart 패턴이 필요하다는 결론.

자바 진영의 rolling restart (Kubernetes Deployment 의 maxUnavailable) 와 같은 개념인데, 단일 프로세스 안의 worker pool 단위에서 같은 패턴을 적용해야 한다. JVM 내부에서는 거의 마주치지 않던 문제.

정리

자바 ThreadPool 사용자가 Python multi-process worker pool 로 옮길 때 외워둘 한 줄.

Python ML 워크로드는 GIL 때문에 thread 가 아닌 process 단위로 격리한다. process 는 비싸므로 worker 라이프사이클 (spawn, initialize, recycle) 이 핵심 비용이고, 모든 운영 문제 (503 폭풍, 메모리 누수, 워밍업 누적) 가 그 라이프사이클의 변형으로 환원된다.

다음 글은 이 위에서 OCR 파이프라인이 어떻게 동작하는지 (layout detection → text recognition → post-processing) 정리한다. ML 모델 추론의 실제 흐름을 보여주는 단계.

참고

  • concurrent.futures — ProcessPoolExecutor
  • Python multiprocessing — Contexts and start methods
  • NVIDIA Multi-Process Service (MPS)
  • PyTorch — Distributed and parallel training
  • Real Python — Speed Up Your Python Program with Concurrency
on this page
  • 01왜 thread 가 아니라 process 인가 — GIL 의 결정
  • 02ProcessPoolExecutor 의 동작
  • 03워커 라이프사이클
  • 04MAX_TASKS_PER_WORKER 의 트레이드오프
  • 05NVIDIA MPS — multi-process GPU 효율화
  • 06Round-Robin GPU 스케줄링
  • 07Worker death monitor — 자바엔 없는 패턴
  • 08restart-all-at-once 패턴의 함정
  • 09정리
  • 10참고

이런 글도

  • Python 서버의 RSS 가 안 줄어드는 이유 — gc.collect 의 한계와 malloc_trim
    Python 으로 long-running 서버 (FastAPI / Flask / Celery / uWSGI 등) 를 운영하다 보면 한 번쯤 마주치는 증상이 있다. - 워커 프로세스의 RSS 가 시간이 지날수록 단조 증가한다 - 큰 객체를 del 하고 gc.collect() 를 불러도 RSS 가 줄지 않는다 - 결국 max-requests / workerma...
    📁 system
    system
    2026.05.22
  • ML 서비스 성능 분석 워크플로 — 자바 백엔드 트러블슈팅과 다른 점
    이 시리즈의 마무리 글이다. 앞선 글들에서 다음 주제를 자바 백엔드 비교 관점으로 정리했다. - Python 문법 - 의존성 관리 - FastAPI - async/await - GPU·CUDA·MPS - PyTorch - multi-process worker pool - OCR 파이프라인 마지막은 이 모든 개념을 적용해 실제 ML 서비스의 성능을 분석하는...
    📁 system
    system
    2026.05.19
  • OCR 동작 원리 — Layout · Text · Post-process 3단계
    자바 백엔드만 다뤄오다가 OCR (Optical Character Recognition) 서비스를 분석할 일이 생겼다. "이미지에서 글자를 뽑는다" 라는 한 줄 요약은 알았지만, 실제 코드를 열어보면 모델이 둘이상이고, 여러 단계가 직렬·병렬로 엮여 있고, "왜 이 단계가 따로 있지" 같은 의문이 계속 생긴다. 이 글은 OCR 파이프라인의 표준 구조를 정리...
    📁 system
    system
    2026.05.19
  • PyTorch 기초 — 텐서, 디바이스, 그리고 모델 로딩이 무거운 이유
    자바 백엔드에서 Spring Boot 가 부팅하는 시간이 5-30초 걸리는 게 일반적이다. 클래스 로딩, 컴포넌트 스캔, 의존성 주입, EntityManagerFactory 초기화 등이 누적된다. 한 번 부팅하면 그 뒤로는 요청 처리에 거의 영향이 없다. PyTorch 기반 ML 서비스는 비슷하지만 한 단계 더 무겁다. 우리 프로젝트의 KR Worker 가...
    📁 system
    system
    2026.05.19

댓글 (0)