Python 비동기 처리에서 asyncio.gather vs asyncio.wait 선택하기
문제 상황
결제 처리 API에서 동시에 여러 외부 서비스(재고 확인, 포인트 조회, 쿠폰 검증)를 호출해야 했다. asyncio를 사용하기로 했는데 gather와 wait 중 어떤 것을 써야 할지 명확하지 않았다.
asyncio.gather의 특징
results = await asyncio.gather(
check_inventory(product_id),
get_user_points(user_id),
validate_coupon(coupon_code)
)
inventory, points, coupon = results
- 모든 태스크가 완료될 때까지 대기
- 결과를 순서대로 반환
- 하나라도 실패하면 즉시 예외 발생 (return_exceptions=False)
- 간결한 코드
asyncio.wait의 특징
tasks = [
asyncio.create_task(check_inventory(product_id)),
asyncio.create_task(get_user_points(user_id)),
asyncio.create_task(validate_coupon(coupon_code))
]
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
for task in done:
result = task.result()
- 완료 조건을 세밀하게 제어 가능 (ALL_COMPLETED, FIRST_COMPLETED, FIRST_EXCEPTION)
- Task 객체 집합을 반환
- 타임아웃 처리가 더 유연
선택 기준
결국 우리 케이스에서는 gather를 선택했다. 세 API 모두 필수였고, 하나라도 실패하면 결제를 진행할 수 없었기 때문이다.
try:
inventory, points, coupon = await asyncio.gather(
check_inventory(product_id),
get_user_points(user_id),
validate_coupon(coupon_code)
)
except Exception as e:
return {"error": "validation_failed"}
반면 알림 발송처럼 일부 실패해도 괜찮은 경우는 gather(return_exceptions=True) 또는 wait를 사용하는 게 맞다.
결론
- 모든 결과가 필요하고 순서가 중요하면
gather - 타임아웃이나 부분 완료 처리가 필요하면
wait - 대부분의 경우
gather가 더 직관적이다