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

Объект Future модуля asyncio Python и связанные функции

Future - объект ждущий результатов выполнения задачи

Объекты Future используются для соединения низкоуровневого кода, основанного на обратном вызове, с высокоуровневым кодом, основанном на синтаксисе async/await.

Содержание:


Объект Future.

asyncio.Future(*, loop=None):

Класс asyncio.Future() представляет собой конечный результат асинхронной операции. Не потокобезопасный.

Объект Future - awaitable объект. Сопрограммы, обернутые в объект asyncio.Future при помощи создания задач, находятся в состоянии ожидания, пока не будет получен результат или исключение, или пока они не будут отменены.

Обычно, объекты Futures используются для того, чтобы код, основанный на обратном вызове низкого уровня мог взаимодействовать с кодом высокого уровня, основанного на синтаксисе async/await. Например, в протоколах, реализованных с использованием транспорта asyncio.

Практическое правило - никогда не раскрывать объекты Future в пользовательских API, а рекомендуемый способ создания объекта Future - вызвать метод loop.create_future(). Таким образом, альтернативные реализации цикла событий могут внедрять свои собственные оптимизированные реализации объекта Future.

Важно. Объект Future был разработан для имитации concurrent.futures.Future().

Ключевые отличия этих объектов:

Методы объекта asyncio.Future():


Future.result():

Метод Future.result() возвращает результат выполнения сопрограммы, обернутой в объект Future.

  • Если объект Future завершен и имеет результат, установленный методом Future.set_result(), то возвращает результирующее значение.
  • Если объект Future выполнен и имеет исключение, установленное методом Future.set_exception(), то метод Future.result() вызывает исключение.
  • Если объект Future был отменен, то этот метод вызывает исключение CancelledError.
  • Если результат Future еще не получил результаты от сопрограммы, этот метод вызывает исключение InvalidStateError.

Future.set_result(result):

Метод Future.set_result() помечает объект Future как выполненный и присваивает ему результат из аргумента result.

Вызывает ошибку InvalidStateError, если объект Future уже выполнен.

Future.set_exception(exception):

Метод Future.set_exception() помечает объект Future как выполненный и устанавливает исключение из аргумента exception.

Вызывает ошибку InvalidStateError, если объект Future уже выполнен.

Future.done():

Метод Future.done() возвращает True, если объект Future уже выполнен.

Объект Future считается выполненным, если он был отменен или если он имеет результат или исключение, установленное с помощью вызова Future.set_result() или Future.set_exception().

Future.cancelled():

Метод Future.cancelled() возвращает True, если объект Future был отменен.

Этот метод используется, для проверки, не отменен ли Future перед тем, как установить для него результат или исключение:

if not fut.cancelled():
    fut.set_result(42)

Future.add_done_callback(callback, *, context=None):

Метод Future.add_done_callback() добавляет обратный вызов callback, который будет запускаться, когда объект Future будет выполнен.

Обратный вызов callback вызывается с объектом Future в качестве единственного аргумента.

Если Future уже выполняется, то при вызове этого метода, обратный вызов планируется с помощью метода loop.call_soon().

Необязательный ключевой аргумент context, позволяет указать настраиваемый contextvars, представляющий контекст выполнения обратного вызова callback. Когда аргумент callback не предоставлен, то используется текущий контекст.

Для передачи параметров в обратный вызов, может использоваться функция functools.partial(), например:

# Вызов 'print('Future:', fut)', когда 'fut' будет выполнен.
fut.add_done_callback(
    functools.partial(print, "Future:"))

Future.remove_done_callback(callback):

Метод Future.remove_done_callback() удаляет обратный вызов callback из списка обратных вызовов.

Возвращает количество удаленных обратных вызовов, которое обычно равно 1, если обратный вызов callback не был добавлен более одного раза.

Future.cancel():

Метод Future.cancel() отменяет выполнение объекта Future и планирует установленные обратные вызовы.

Если объект Future уже выполнен или отменен, то возвращает False. В противном случае изменяет состояние Future на "отменено", планирует обратные вызовы и возвращает True.

Future.exception():

Метод Future.exception() возвращает исключение, которое было установлено для этого объекта Future.

Исключение (или None, если исключение не было установлено) возвращается только в том случае, если объект Future помечен как выполненный.

Future.get_loop():

Метод Future.get_loop() возвращает цикл событий, к которому привязан объект Future.

Новое в Python 3.7.

Пример создания и использования Future в низкоуровневом коде.

import asyncio

def mark_done(future, result):
    print(f'Установка результата `future`')
    future.set_result(result)

async def main(loop):
    # создание объекта `Future`
    future = loop.create_future()
    # планирование асинхронного выполнения `mark_done()`
    loop.call_soon(mark_done, future, 'RESULT')
    print('Приостановка работы сопрограммы')
    result = await future
    print(f'Результат из `future`: {future.result()!r}')
    return result

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    try:
        print('Вход в цикл событий')
        result = loop.run_until_complete(main(loop))
        print(f'Результат из цикла событий: {result!r}')
    finally:
        loop.close()
  
        
# Вход в цикл событий
# Приостановка работы сопрограммы
# Установка результата `future`
# Результат из `future`: 'RESULT'
# Результат из цикла событий: 'RESULT'

Связанные функции с объектом Future.

asyncio.isfuture(obj):

Функция asyncio.isfuture() возвращает True, если:

  • аргумент obj это экземпляр asyncio.Future,
  • аргумент obj это экземпляр asyncio.Task(),
  • аргумент obj это Future-like объект, т. е. похож на объект Future и имеет атрибут _asyncio_future_blocking.

asyncio.ensure_future(obj, *, loop=None):

Функция asyncio.ensure_future() принимает аргумент obj, который должен представлять из себя любой объект ожидания - awaitable. Другими словами функция создает задачи, подробнее смотрите примечание ниже.

Функция возвращает:

  • аргумент obj как есть, если obj является объектом Future, Task или Future-like объектом (для проверки используется функция asyncio.isfuture()).
  • создаст задачу Task, если obj является сопрограммой (для проверки используется asyncio.iscoroutine(obj)). В этом случае сопрограмма будет запланирована с помощью этой функции asyncio.ensure_future().
  • объект Task, который будет ждать аргумент obj, если obj является объектом awaitable (для проверки используется функция inspect.isawaitable(obj)).

Если аргумент obj не является ни тем, ни другим из вышеперечисленного, то возникает ошибка TypeError.

Примечание. Ответ Гвидо по поводу этой функции: смысл asyncio.ensure_future() в том, что если есть что-то, что может быть либо сопрограммой, либо Future (последнее включает Task, потому что это подкласс Future), и необходимо иметь возможность вызывать для него метод, который определен ТОЛЬКО для объекта Future (вероятно, единственный полезный пример - Future.cancel()). В общем, когда передается объект Future или Task, то эта функция ничего не делает. Когда передается сопрограмма, то она оборачивается ее в задачу Task.

Если есть сопрограмма, и необходимо запланировать ее выполнение, правильный API для использования - asyncio.create_task(). Единственный раз, когда вы должны вызывать asyncio.ensure_future(), - это когда разработчик предоставляет пользователю API, который принимает либо сопрограмму, либо Future, с которым нужно что-то сделать.

Важно: предпочтительным способом создания новых задач является функция asyncio.create_task().


asyncio.wrap_future(future, *, loop=None):

Функция asyncio.wrap_future() оборачивает объект concurrent.futures.Future() в объект asyncio.Future.