asyncio는 한 스레드의 이벤트 루프에서 많은 I/O 작업이 기다림을 양보하도록 한다. `async def`를 호출하면 결과가 아니라 coroutine 객체를 얻는다.

import asyncio

async def fetch(name: str) -> str:
    await asyncio.sleep(0.1)
    return name

async def main():
    results = await asyncio.gather(fetch("a"), fetch("b"))
    print(results)

asyncio.run(main())

블로킹 파일·네트워크 라이브러리를 async 함수 안에서 그대로 부르면 이벤트 루프 전체가 멈춘다. 비동기 라이브러리를 쓰거나 `asyncio.to_thread`로 제한해 보낸다.

Python 3.11의 TaskGroup은 자식 작업의 수명을 한 블록에 묶는 구조적 동시성을 제공한다. 하나가 실패하면 형제 작업을 취소하고 예외 그룹으로 전달한다.

취소는 `CancelledError`로 전달된다. 넓은 예외 처리로 삼키지 말고 정리 후 다시 올린다. timeout과 동시 요청 수 제한은 운영 비동기 코드의 필수 경계다.

Python 24. asyncio와 비동기 I/O의 핵심 흐름도
그림. asyncio는 I/O 대기 동안 다른 coroutine을 진행시킨다.