[멀티 프로세스] 단일 프로세스, 멀티 프로세스 성능 비교(리소스 사용량, 테스크별 지연시간) - 100-hours-a-week/5-yeosa-wiki GitHub Wiki
1. 개요
- 멀티 프로세스에서 오히려 지연 시간이 늘어남. (gpu 서버에서 병목 발생)
- 해당 원인을 아래와 같이 예측함.
- 단일 프로세스에서는 cpu 바운드 테스크가 병목 지점
- 멀티 프로세스에서는 i/o 바운드 테스크가 병목 지점
(cpu, gpu 리소스는 풀로 이용하고 있기 때문)
- 할 일:
- gpu 서버의 단일 프로세스, 멀티 프로세스에서 리소스 사용량, 지연 시간(이미지 로딩, 디코딩, 전처리) 측정
- 멀티 프로세스에서 식별한 병목 지점 개선
2. 로깅 추가
a. 이미지 1장 로딩
async def _download(self, file_name: str) -> bytes:
"""
GCS에서 단일 이미지를 다운로드하고 RGB로 변환합니다.
Args:
file_name (str): GCS 내 파일 이름
Returns:
bytes: 로드된 이미지 바이트
"""
start = time.time()
image_bytes = await self.client.download(
bucket=self.bucket_name, object_name=file_name
)
end = time.time()
print(f"[INFO] 이미지 로딩 완료 : {format_elapsed(end - start)}")
#
return image_bytes
b. 이미지 디코딩
# 공통 디코더
def decode_image_cv2(image_bytes: bytes, label: str) -> np.ndarray:
start = time.time()
nparr = np.frombuffer(image_bytes, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
end = time.time()
print(f"[INFO] 디코딩 완료 : {format_elapsed(end - start)}")
return img
c. 이미지 전처리 & 임베딩
import torch
import time
from concurrent.futures import ThreadPoolExecutor
def format_elapsed(t: float) -> str:
return f"{t * 1000:.2f} ms" if t < 1 else f"{t:.2f} s"
def embed_images(
model, preprocess, images, filenames, batch_size=32, device="cuda"
):
# 이미지 전처리를 배치 단위로 수행
preprocessed_batches = []
t1 = time.time()
for i in range(0, len(images), batch_size):
batch_images = images[i:i + batch_size]
preprocessed_batch = preprocess(batch_images)
preprocessed_batches.append(preprocessed_batch)
t2 = time.time()
print(f"[INFO] 전처리 완료: {format_elapsed(t2 - t1)}")
# 결과를 저장할 딕셔너리
results = {}
t3 = time.time()
# 배치 단위로 임베딩 수행
for i, batch in enumerate(preprocessed_batches):
batch_filenames = filenames[i * batch_size:(i + 1) * batch_size]
# GPU로 데이터 이동
image_input = batch.to(device)
# 임베딩 생성
with torch.no_grad():
batch_features = model.encode_image(image_input)
# CPU로 결과 이동 및 저장
batch_features = batch_features.cpu()
for filename, feature in zip(batch_filenames, batch_features):
results[filename] = feature.cpu()
t4 = time.time()
print(f"[INFO] 임베딩 완료: {format_elapsed(t4 - t3)}")
return results
3. 테스트 결과
- 추후 리소스 재확인용 테스트 시간 기록
- 6.11 3시 45분~55분: multiprocess
- 6.11 5시 11분~5시 21분: singleprocess

single process |
gpu |
cpu |
gpu mem |
cpu mem |
% |
86.96 |
80.06 |
33.23 |
53.07 |
multi process |
gpu |
cpu |
gpu mem |
cpu mem |
% |
98.9 |
91.73 |
32.85 |
66.59 |
- multi process에서 spawn() 시스템 콜로 모델 로딩함에 따라 cpu 메모리 이용량 증가
- gpu 메모리는 늘지 않은 이유:
- torch는 “사용 시점에만” gpu 메모리 점유
b. k6 report
가. multi process

나. single process

c. 테스크별 처리 시간
| | single process | multi process | 비교 (single→multi) |
| --- | --- | --- | --- |
| 디코딩 | 단일: 15.78 ms
최소값: 7.27 ms
평균값: 24.80 ms
최대값: 278.22 ms
| 단일: 16.18 ms
최소값: 6.86 ms
평균값: 30.47 ms
최대값: 380.92 ms | 평균 +22.9% |
| 로딩 | 단일: 232.66 ms
최소값: 10.08 ms
평균값: 204.48 ms
최대값: 541.40 ms | 최소값: 1.09 ms
평균값: 105.82 ms
최대값: 996.07 ms | 평균 -48.2% |
| 로딩 및 디코딩 | 단일: 232.66 ms
최소값: 76.89 ms
평균값: 300.36 ms
최대값: 647.85 ms | 단일: 238.69 ms
최소값: 1.01 ms
평균값: 320.69 ms
최대값: 985.95 ms | 평균 +6.8% |
| 전처리 | 단일: 63.96 ms
최소값: 36.01 ms
평균값: 105.93 ms
최대값: 641.05 ms | 단일: 66.06 ms
최소값: 1.04 ms
평균값: 262.54 ms
최대값: 991.44 ms | 평균 +147.7% |
| 임베딩 | 단일: 183.38 ms
최소값: 66.22 ms
평균값: 218.94 ms
최대값: 562.11 ms | 단일: 183.63 ms
최소값: 1.00 ms
평균값: 466.93 ms
최대값: 999.76 ms | 평균 +113.3% |
- 멀티 프로세스 전환 후, 평균 처리 시간은 대체로 증가
- 특히 전처리, 임베딩에서 2배 이상 증가
- i/o 바운드 테스크인 로딩은 2배 감소
- cpu, gpu 리소스를 풀로 이용함에 따라 리소스 경합이 심화되어 오버헤드 증가
4. 결론: gpu 서버 워커 프로세스 2개로 감축 예정
- cpu, gpu 리소스가 워커 프로세스 3개를 감당하기에 충분치 않음
- 워커 프로세스를 3 → 2개로 줄여서 i/o 속도 개선을 누리면서
리소스 경합을 완화하여 연산 중심 테스크에서도 속도 개선 달성하고자 함