asyncio API의 await 키워드 뒤에는 Awaitable한 객체가 와야합니다. 이때, Awaitable한 객체란 무엇일까요? Coroutines and Tasks에서 답을 찾아봅시다.

우리는 객체가 await 표현식에서 사용될 수 있을 때 Awaitable 객체라고 말합니다. 많은 asyncio API는 어웨이터블을 받아들이도록 설계되었습니다. Awaitable 객체에는 세 가지 주요 유형이 있습니다: 코루틴태스크 및 퓨처.

coroutine

파이썬 코루틴은 Awaitable이므로 다른 코루틴에서 기다릴 수 있습니다:

import asyncio

async def nested():
    return 42

async def main():
    # Nothing happens if we just call "nested()".
    # A coroutine object is created but not awaited,
    # so it *won't run at all*.
    nested()

    # Let's do it differently now and await it:
    print(await nested())  # will print "42".

asyncio.run(main())

Task

Task는 코루틴을 동시에 예약하는 데 사용됩니다. 코루틴이 asyncio.create_task()와 같은 함수를 사용하여 Task로 싸일 때 코루틴은 곧 실행되도록 자동으로 예약됩니다:

import asyncio

async def nested():
    return 42

async def main():
    # Schedule nested() to run soon concurrently
    # with "main()".
    task = asyncio.create_task(nested())

    # "task" can now be used to cancel "nested()", or
    # can simply be awaited to wait until it is complete:
    await task

asyncio.run(main())

Future

Future는 비동기 연산의 최종 결과를 나타내는 특별한 저수준 어웨이터블 객체입니다. Future 클래스는 Task의 상위 클래스로 루프와 관련된 모든 기능을 제공합니다. Future는 어떤 동작의 미래에 일어날 완료 상태를 나타내고 루프에 의해 관리됩니다. (=Future 객체를 기다릴 때, 그것은 코루틴이 Future가 다른 곳에서 해결될 때까지 기다릴 것을 뜻합니다.) 콜백 기반 코드를 async/await와 함께 사용하려면 asyncio의 Future 객체가 필요합니다. 일반적으로 응용 프로그램 수준 코드에서 Future 객체를 만들 필요는 없다고 합니다.

때때로 라이브러리와 일부 asyncio API에 의해 노출되는 Future 객체를 기다릴 수 있습니다:

async def main():
    await function_that_returns_a_future_object()

    # this is also valid:
    await asyncio.gather(
        function_that_returns_a_future_object(),
        some_python_coroutine()
    )

Future 인스턴스의 기능

  • 'result' 값을 설정할 수 있다. (값을 쓸 때는 .set_result(value)를 사용하고, 값을 읽어올 때는 .result()를 사용)
  • .cancel()로 작업을 취소할 수 있다. (.cancelled()로 취소 여부 확인)
  • Future가 완료되었을 때 실행할 콜백 함수들을 가진다.

Task를 사용하는 편이 더 일반적이지만 Future를 사용해야 하는 경우도 있습니다. loop.run_in_executor()를 사용할 때는 Future 인스턴스를 반환 받습니다.

정리

             ┌──Coroutine
             │
Awaitable◄───┤
             │
             └──Future◄────────Task

await 키워드를 붙일 수 있는 최소 조건이 Awaitable입니다. 그래서 3가지 모두 await으로 실행이 끝나길 기다릴 수 있습니다. 하지만 코루틴은 Eventloop에 등록되지 않으면 실행되지 않기 때문에, await을 붙이거나 FutureTask로 감싸야 합니다.


References

https://docs.python.org/3/library/asyncio-task.html#awaitables