Объекты Future
используются для соединения низкоуровневого кода, основанного на обратном вызове, с высокоуровневым кодом, основанном на синтаксисе async
/await
.
asyncio.Future()
- ОБЪЕКТ Future
и его методы.Future
:asyncio.isfuture()
- проверяет на объект Future
,asyncio.ensure_future()
- оборачивает сопрограмму в задачу,asyncio.wrap_future()
- оборачивает concurrent.futures.Future()
.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 Futures
, экземпляры concurrent.futures.Future
нельзя ожидать.Future.result()
и Future.exception()
не принимают аргумент таймаута.Future
не выполняется, то методы Future.result()
и Future.exception()
вызывают исключение asyncio.InvalidStateError
.Future.add_done_callback()
, планируются с помощью loop.call_soon()
.asyncio.Future
несовместим с функциями concurrent.futures.wait()
и concurrent.futures.as_completed()
.asyncio.Future()
:Future
Future.result()
,Future
Future.set_result()
,Future
Future.set_exception()
,Future
на выполнение Future.done()
,Future
на отмену выполнения Future.cancelled()
,Future.add_done_callback()
,Future.remove_done_callback()
,Future
Future.cancel()
,Future.exception()
,Future.get_loop()
,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
был отменен, то этот метод вызывает исключение CancelledError
.Future
еще не выполнен, то этот метод вызывает исключение InvalidStateError
.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
.