Python 비동기 처리에서 asyncio.gather vs asyncio.as_completed 선택 기준
문제 상황
외부 API 100개를 호출해서 데이터를 수집하는 배치 작업이 있었다. 초기에는 asyncio.gather로 구현했는데, 전체 작업이 완료될 때까지 아무런 피드백이 없어서 진행 상황 파악이 어려웠다.
asyncio.gather의 특성
import asyncio
async def fetch_data(id):
await asyncio.sleep(1) # API 호출 시뮬레이션
return f"Data {id}"
async def main():
tasks = [fetch_data(i) for i in range(100)]
results = await asyncio.gather(*tasks)
# 모든 작업이 완료된 후 한 번에 결과 반환
print(len(results))
gather는 모든 코루틴이 완료될 때까지 대기하고, 입력 순서대로 결과를 리스트로 반환한다. 순서 보장이 필요하거나 모든 결과를 한 번에 처리할 때 유용하다.
asyncio.as_completed로 개선
async def main_improved():
tasks = [fetch_data(i) for i in range(100)]
for coro in asyncio.as_completed(tasks):
result = await coro
print(f"완료: {result}")
# DB 저장, 로깅 등 즉시 처리 가능
as_completed는 완료되는 순서대로 결과를 yield한다. 장시간 실행되는 작업에서 중간 진행 상황을 확인하거나, 완료된 결과부터 즉시 처리해야 할 때 적합하다.
실무 적용 기준
- gather 사용: 순서 보장 필요, 결과 일괄 처리, 에러 핸들링 단순화
- as_completed 사용: 진행 상황 모니터링, 스트리밍 처리, 메모리 효율
최종적으로 as_completed로 변경했고, tqdm을 추가해서 진행률을 실시간으로 확인할 수 있게 개선했다. 배치 작업의 가시성이 크게 향상되었다.