Сообщить об ошибке.

Что такое аwaitable объект модуля asyncio в Python

Аwaitable объекты - это объекты, ожидающие результатов

В асинхронном программировании принято говорить, что объект является awaitable, то есть это объект, который, в какой-то момент времени может ничего полезного не делать, а заниматься только ожиданием каких-то результатов от сторонних сервисов (например ответа сервера с результатами на свой запрос). Такие объекты всегда запускаются с оператором await.

Практически все API-интерфейсы модуля asyncio предназначены для приема awaitable объектов - объектов ждущих каких-то результатов или команд на продолжение или приостановку работы от основного цикла событий.

Есть три основных типа объектов ожидания awaitable, которые можно запускать оператором await в асинхронном коде:

Сопрограммы/сoroutines.

Сопрограммы в Python являются объектами, которые могут ждать результатов от сторонних сервисов или своей очереди выполнения, следовательно, их можно также использовать с оператором wait внутри других сопрограмм:

import asyncio

async def nested():
    return 42

async def main():
    # Ничего не происходит, если мы просто вызываем "nested()".
    # Сопрограмма `nested()` создается, но не будет выполняться,
    # т.к. в таком виде она заблокирует цикл событий, что недопустимо
    nested()

    # что бы асинхронная функция `nested()` заработала
    # необходимо заставить ее ждать своего выполнения 
    # при помощи оператора `await`
    print(await nested())

asyncio.run(main())

# 42

Важно. Здесь термин "сопрограмма" может использоваться для двух тесно связанных понятий:

  • функция сопрограммы: функция, определенная как *async def*;
  • объект сопрограммы: объект, возвращаемый вызовом функции сопрограммы.

Примечание:

Модуль asyncio также поддерживает устаревшие сопрограммы на основе генератора. Поддержка сопрограмм на основе генераторов запланирована к удалению в Python 3.10.

Задачи Task.

Задачи (asyncio.Task) используются для одновременного планирования запуска нескольких сопрограмм. Когда сопрограмма оборачивается в задачу (передается в функцию asyncio.create_task()), то сопрограмма будет автоматически запускаться в ближайшее время, как только будет это возможным:

import asyncio

async def nested():
    return 42

async def main():
    # Запланируем запуск 'nested()' в одновременно с 'main()'.
    task = asyncio.create_task(nested())

    # объект 'task' может теперь использоваться, для отмены
    # выполнения 'nested()' или ожидания ее выполнения:
    await task

asyncio.run(main())
# 42

Запуск задачи всегда происходит оператором await, т. к. она будет ждать своего выполнения.

Futures - объекты с будущими результатами.

Future объект - инкапсулирует асинхронное выполнение вызываемого объекта и представляет специальный низкоуровневый объект, который хранит промежуточное состояние запущенной задачи (когда она что-то ожидает) и в будущем, будет представлять конечный результат асинхронной операции. Этот объект может хранить информацию о том, что задача ещё не выполнена или не до конца выполнена, или может хранить уже полученный результат, или исключение, полученное во время выполнения кода.

Когда происходит ожидание объекта Future , это означает, что сопрограмма будет ждать, пока Future не будет разрешен в каком-то другом месте.

Futures объекты позволяют использовать код на основе обратного вызова (который сообщает о готовности объекта Future) совместно с синтаксисом async/await, по этому они необходимы в асинхронном программировании.

Нет необходимости создавать объекты Future на уровне приложения. В основном, эти объекты создаются автоматически, при вызове функций или методов, предоставляемыми асинхронными API модулей:

async def main():
    await function_that_returns_a_future_object()

    # это тоже правильно:
    await asyncio.gather(
        function_that_returns_a_future_object(),
        some_python_coroutine()
    )

Хорошим примером низкоуровневой функции, возвращающей Future объект, является функция loop.run_in_executor().