
파이썬 asyncio는 언제 필요할까요? 답은 ‘작업이 많을 때’가 아니라 ‘기다리는 시간이 많을 때’입니다. asyncio는 CPU를 여러 개로 나눠 쓰는 병렬성 도구가 아니라, I/O 대기 시간을 겹쳐 쓰는 동시성 도구에 가깝습니다.
이 차이를 모르면 async/await를 쓰고도 코드가 더 어려워지기만 합니다. 특히 API 호출, 웹 요청, DB I/O처럼 기다림이 많은 작업과 이미지 처리, 대량 계산처럼 CPU를 많이 쓰는 작업을 구분해야 합니다. 파이썬 기본 문법 흐름은 파이썬 리스트 컴프리헨션 글과 함께 보면 좋습니다.

파이썬 asyncio를 한 줄로 정리
Python 공식 asyncio 문서는 asyncio를 async/await 문법으로 concurrent code를 작성하기 위한 라이브러리로 설명합니다. 그리고 IO-bound 작업과 high-level structured network code에 잘 맞는다고 설명합니다.
즉 asyncio는 동시에 여러 일을 ‘진짜로 병렬 실행’한다기보다, 한 작업이 네트워크 응답을 기다리는 동안 다른 작업을 진행하게 해주는 방식입니다.
동시성과 병렬성 차이
동시성은 여러 일을 번갈아 처리하는 능력이다
동시성은 한 사람이 여러 작업을 번갈아 처리하는 것과 비슷합니다. 이메일 답장을 기다리는 동안 문서를 쓰고, 파일 다운로드를 기다리는 동안 다음 요청을 준비하는 식입니다. 한 순간에 하나만 하더라도 전체 시간은 줄어들 수 있습니다.
병렬성은 여러 일을 실제로 동시에 처리하는 능력이다
병렬성은 여러 CPU 코어가 계산을 나눠서 동시에 처리하는 것입니다. 이미지 변환, 압축, 머신러닝 전처리, 큰 숫자 계산처럼 CPU를 계속 쓰는 작업은 asyncio만으로 빨라지기 어렵습니다.
- I/O bound: 네트워크, 파일, DB 응답을 기다리는 시간이 길다
- CPU bound: 계산 자체가 오래 걸린다
- asyncio: I/O bound 작업을 많이 겹칠 때 유리하다
- multiprocessing: CPU bound 작업을 여러 코어로 나눌 때 검토한다
asyncio가 잘 맞는 예
여러 URL을 순서대로 요청하면 각 요청의 대기 시간이 그대로 쌓입니다. 반면 asyncio에서는 요청을 task로 만들고 기다리는 시간을 겹칠 수 있습니다.
import asyncio
async def fetch_user(user_id: int) -> str:
await asyncio.sleep(1) # 실제 코드에서는 HTTP 요청 대기
return f"user-{user_id}"
async def main():
task1 = asyncio.create_task(fetch_user(1))
task2 = asyncio.create_task(fetch_user(2))
task3 = asyncio.create_task(fetch_user(3))
users = await asyncio.gather(task1, task2, task3)
print(users)
asyncio.run(main())중요한 점은 fetch_user 안에서 CPU가 바쁘게 계산하는 것이 아니라 기다리는 시간이 있다는 것입니다. 이 기다림이 있어야 event loop가 다른 task로 넘어갈 여지가 생깁니다.
asyncio가 잘 맞지 않는 예
아래처럼 순수 계산이 오래 걸리는 함수는 await를 붙인다고 자동으로 빨라지지 않습니다. CPU를 계속 붙잡고 있으면 event loop가 다른 coroutine으로 넘어가기 어렵습니다.
def count_heavy(n: int) -> int:
total = 0
for i in range(n):
total += i * i
return total이런 작업은 multiprocessing, native extension, vectorized library, 작업 큐 분리 같은 방법을 먼저 검토하는 편이 낫습니다. asyncio는 기다림을 잘 다루는 도구이지, 계산량 자체를 줄이는 도구가 아닙니다.
async/await를 쓸 때 자주 하는 실수
- coroutine 함수를 호출만 하고 await하지 않는다
- blocking 라이브러리를 async 함수 안에서 그대로 호출한다
- CPU bound 작업을 asyncio로 해결하려고 한다
- 동시 실행 수 제한 없이 외부 API를 너무 많이 호출한다
- 예외와 cancellation 처리를 하지 않는다
Python 공식 Coroutines and Tasks 문서는 coroutine을 단순히 호출하는 것만으로는 실행이 예약되지 않는다고 설명합니다. 실제 실행은 await, asyncio.run, create_task 같은 경로를 통해 이뤄져야 합니다.
마무리
파이썬 asyncio는 기다리는 작업이 많을 때 빛납니다. API 호출, 웹 크롤링, 소켓 통신, 비동기 DB 클라이언트처럼 I/O bound 작업이 많다면 async/await를 검토할 가치가 있습니다.
반대로 CPU 계산이 문제라면 asyncio부터 꺼내면 방향이 어긋날 수 있습니다. 먼저 병목이 기다림인지 계산인지 나누고, 기다림이 많을 때 asyncio를 선택하면 됩니다.