개요
2024.06.26-[Python] asyncio - 비동기 프로그래밍에서 asyncio.run, 그리고 await을 이용한 코루틴 실행 방법을 알아보았다. 사실 코루틴 실행 방법은 한 가지 더 존재하는데, 바로 create_task 함수를 이용하는 방법이다.
이번 글에서는 create_task를 이용한 비동기 프로그래밍을 정리한다.
create_task
asyncio.create_task(coro, *, name=None, context=None)
전달받은 코루틴으로 Task 객체를 생성하고 실행을 예약한다. Task 객체를 반환한다.
Task는 get_running_loop으로 반환된 이벤트루프에서 실행되고, 현재 스레드에 실행 중인 이벤트 루프가 없으면 RuntimeError가 발생한다.
보통 여러 개의 코루틴을 동시에 실행시키고 싶을 때 사용하는 것 같다.
예시 )
import asyncio
import time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
task1 = asyncio.create_task(say_after(1, 'hello'))
task2 = asyncio.create_task(say_after(2, 'world'))
print(f"started at {time.strftime('%X')}")
# Wait until both tasks are completed (should take around 2 seconds.)
await task1
await task2
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
create_task vs await
create_task, await 모두 코루틴을 실행시키지만 두 방법에는 약간의 차이가 있다.
create_task는 create_task 시점에 바로 코루틴의 실행을 예약한다. 따라서 위의 예시 코드는 다음과 같이 동작한다
- asyncio.run(main()) : 비동기 진입
- task1 : say_after(1, 'hello') 생성 및 실행 예약
- task2 : say_after(2, 'world') 생성 및 실행 예약
- await task1, await task 2 : 실행 대기
코루틴의 실행은 create_task에 이미 진행되고 있고, await는 단지 완료를 대기한다.
반면 await의 경우 코루틴을 실행시킨 후 반환을 기다린다. 아래 코드는 say_after를 await으로 호출하도록 변경한 것이다.
import asyncio
import time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
print(f"started at {time.strftime('%X')}")
await say_after(1, 'hello')
await say_after(2, 'world')
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
이때의 동작은 다음과 같다.
- asyncio.run(main()) : 비동기 진입
- await say_after(1, 'hello') : 코루틴 실행 및 대기
- await say_after(2, 'world') : 코루틴 실행 및 대기
task를 생성하고 실행을 바로 예약하는 create_task와 다르게 await는 코루틴을 실행하고 완료를 대기한다. 결과적으로 두 개의 작업에 2초가 소요되는 create_task와 달리 await는 3초가 소요된다.
달리 말하면, 아래의 두 메인 함수는 본질적으로 동일하다.
async def main():
await say_after(1, 'hello')
async def main():
task1 = asyncio.create_task(say_after(1, 'hello'))
await task1