Python 비동기 처리에서 asyncio.gather vs asyncio.wait 선택하기

문제 상황

결제 처리 API에서 동시에 여러 외부 서비스(재고 확인, 포인트 조회, 쿠폰 검증)를 호출해야 했다. asyncio를 사용하기로 했는데 gatherwait 중 어떤 것을 써야 할지 명확하지 않았다.

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가 더 직관적이다
Python 비동기 처리에서 asyncio.gather vs asyncio.wait 선택하기