awaitable 은 파이썬에서 await 키워드를 사용할 수 있는 객체들을 의미한다. 이들은 await 를 통해서 실행이 완료되기 전에 다른 작업으로 전환이 가능하다. awaitable 한 객체들은 Coroutines, Tasks, Futures 의 세종류가 있다.
1. Coroutines
파이썬 코루틴은 asyncio 라이브러리 내에 정의된 비동기 코루틴으로 async def 키워드를 사용하여 정의된 함수가 리턴하는 객체이다. 일반적으로 coroutine 이라는 용어는 async def 함수와 해당 함수가 반환하는 객체를 지칭하는 의미로 혼용된다.
import asyncio
async def nested():
return 42
async def main():
nested() # 아무 일도 일어나지 않는다.
print(await nested()) # 42
asyncio.run(main())
위의 예제에서 nested() 를 호출하면 아무 일도 일어나지 않는다. 그저 코루틴 객체만 반환하게 된다. 반환된 코루틴 객체를 실행하기 위해서는 await 를 붙여서 해당 작업을 실행하고 결과를 기다리는 동작을 명시해야 한다.
※ await 키워드는 일반 함수에서는 사용할 수 없고, 반드시 코루틴 함수 내에서만 사용할 수 있다.
2. Tasks
Task 는 Coroutine 을 동시적으로 실행할 수 있도록 스케줄링하기 위해 사용된다. asyncio.create_task() 함수에 코루틴 객체를 전달하면 해당 코루틴 객체가 Task 로 포장된다. 이렇게 생성된 Task 는 자동으로 스케줄링되어서 가능한 시점에 실행된다.
import asyncio
async def nested():
return 42
async def main():
task = asyncio.create_task(nested()) # nested() 코루틴 객체가 실행되도록 스케줄링한다.
print(await task) # 42
asyncio.run(main())
위의 예제에서는 asyncio.create_task() 함수를 사용하여 nested() 로 코루틴 객체를 Task 로 만든다. 그리고 await task 로 반환된 Task 객체를 실행하도록 한다.
3. Futures
Future 는 비동기 동작의 이벤트성 결과를 표현하는 low-level 의 awaitable 객체이다. Future 객체가 await 되면 다른 위치에서 동작중인 코루틴이 작업을 완료하여 Future 가 해결될 때까지 다른 coroutine 은 대기한다.
Future 객체는 주로 async/await 과 함께 사용될 콜백 기반의 코드에 사용되며, 애플리케이션 레벨에서 직접 Future 객체를 만들 필요는 없다. 간혹 asyncio API 를 사용하여 직접 Future 객체가 표현되기도 하는데, 아래의 예제와 같이 await 가 가능하다.
async def main():
await function_that_returns_a_future_object()
await asyncio.gather(
function_that_returns_a_future_object,
some_another_coroutine()
)
4. asyncio 생성 및 작동
- asyncio 프로그램 실행
asyncio.run(coro, *, debug=False) # coro 로 지정된 코루틴을 실행시킨다.
asyncio 객체는 asyncio.run() 메서드로 실행이 가능하다. 이 메서드는 매개변수로 지정된 코루틴을 실행하고 그 결과를 반환한다. 코루틴이 실행될 asyncio 이벤트 루프를 관리하고 비동기 객체의 작업을 완료한 후에 스레드풀을 닫는다.
만약 이미 동일한 스레드에서 다른 이벤트 루프가 작업중인 경우에는 이 함수를 호출할 수 없다.
이 함수는 항상 새로운 이벤트 루프를 생성하고 마지막에는 닫아준다.
- Task 생성
asyncio.create_task(coro, *, name=None) # coro 를 Task 로 포장하고 실행하기 위해 스케줄링한다.
코루틴 coro 를 가지고 Task 객체를 생성하고 이를 스케줄링한다. task 는 get_running_loop() 로 반환되어지는 이벤트 루프에서 실행되며 스케줄링된 후에 적절한 시점에 실행된다.
await task 와 같은 형식으로 실행하여 반환값인 Task 객체를 받을 수 있는데, name 이 None 이 아닌 경우에 Task 의 이름을 name 에 지정된 이름으로 설정한다.
create_future() 함수로 대체가 가능하다.
- sleep, Timeout 지정
coroutine asyncio.sleep(delay, result=None) # delay 로 준 시간만큼 sleep 한다.
delay 초만큼 현재 수행중인 함수를 block 한다. sleep 함수가 제어권을 잡고 지정된 시간동안 현재 작업이 대기한다.
delay 초가 다 지나면 다음 라인으로 넘어간다.
coroutine asyncio.wait_for(aw, timeout)
wait_for 은 지정된 timeout 시간 동안만 지정된 awaitble aw 의 작업 완료를 기다린다. aw 가 코루틴인 경우 자동으로 Task 객체로 변환되어 스케줄링된다.
timeout 은 None 이거나 number 값이 들어가게 되는데, None 인 경우에는 해당 future 가 완료될 때까지 block 된다. 만약 timeout 이 발생하면 작업을 중단하고 asyncio.TimeoutError 를 발생시킨다.
[Reference]
- https://docs.python.org/3/library/asyncio-task.html
- https://soooprmx.com/python-awaitable%EC%97%90-%EB%8C%80%ED%95%B4/
'프로그래밍언어 > Python' 카테고리의 다른 글
[Python] Default Argument Value - mutable object (2) | 2023.12.02 |
---|---|
[Python] GIL (Global Interpreter Lock) (0) | 2022.07.24 |
[Python] Decorator (0) | 2022.04.01 |
[Python] module, package, library (0) | 2022.02.11 |
[Python] copy (0) | 2022.02.08 |