- Asyncio는 Python에서 I/O 바운드 프로그램을 다루는 좋은 방법이며, 기본적으로 Python Generator 위에 좋은 레이어를 제공함
- Generator는 코드를 메모리 효율적으로 만들어 주며,
yield
키워드를 사용해 함수를 일시 중지하고 재개할 수 있음
-
yield from
을 사용하면 generator가 sub-generator나 iterable 객체를 호출할 수 있어 generator 체인을 만들 수 있음
이벤트 루프
- Asyncio의 핵심은 현재 task를 실행하고 관리하는 event loop임
- Event loop는 task 목록을 반복하면서
next(task)
로 각 task를 실행함
- Task는 I/O 작업 중에
yield
를 사용해 실행을 일시 중지하고 제어권을 event loop에 넘김
슬리핑
-
yield from
을 사용해 task에 sub-generator를 추가할 수 있음
- Sleep generator를 추가하면 지정된 시간까지 task 실행을 일시 중지할 수 있음
- Sleep이
while
루프를 빠져나가면 StopIteration
예외가 발생해 task 함수의 yield from
이 다음 코드 줄로 계속 진행됨
Yield에서 Await로
-
__await__
던더 메서드와 async
키워드를 사용해 yield
에서 await
로 전환할 수 있음
-
await
키워드는 클래스 인스턴스의 __await__
메서드를 호출하거나 코루틴(async 함수로 생성된 객체)에서 사용 가능
-
await
키워드는 yield from
의 동의어로 볼 수 있으며 약간의 추가 유효성 검사 규칙이 있음
- 자체
Task
클래스를 만들어 __await__
메서드를 구현하고, create_task
함수로 생성한 task를 이벤트 루프에 추가함
- 이벤트 루프 관리자는 task를 실행하고,
StopIteration
예외 발생 시 task를 완료 처리함
- Sleep 함수도 async 호환되도록 수정해야 함
AsyncIO와 Await
- 위 코드에서 "jacobio"를 "asyncio"로 교체하면 asyncio 패키지를 완전히 사용하게 됨
- Asyncio는 더 많은 작업을 수행하지만, 기본 generator에서 asyncio의 핵심 부분을 처음부터 재현할 수 있음
- 실제 asyncio 패키지에서는
asyncio.gather()
등의 함수를 사용해 여러 task를 처리할 수 있음
GN⁺의 의견
- 이 글은 asyncio의 작동 원리를 generator를 사용해 쉽게 설명하고 있어, asyncio를 처음 접하는 개발자들에게 큰 도움이 될 것 같음
- Asyncio는 고성능 I/O 처리에 최적화된 라이브러리로, 이 글을 통해 그 내부 구조를 이해하면 실제 프로젝트에서 더 효과적으로 활용할 수 있을 것임
- 다만 실제 asyncio는 훨씬 더 복잡한 구조를 가지고 있어, 실무에서 사용하기 위해서는 공식 문서 등을 통해 더 깊이 있는 학습이 필요할 것으로 보임
- Asyncio와 유사한 기능을 제공하는 다른 라이브러리로는 Trio, Curio 등이 있는데, 이들과의 차이점을 비교해 보는 것도 흥미로울 것 같음
- Asyncio를 도입할 때는 기존 동기 코드와의 호환성, 에러 처리, 테스트 등 고려해야 할 사항이 많으므로, 충분한 검토와 준비가 필요할 것으로 보임