1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
|
.. currentmodule:: asyncio
.. _asyncio-futures:
=======
Futures
=======
**Source code:** :source:`Lib/asyncio/futures.py`,
:source:`Lib/asyncio/base_futures.py`
-------------------------------------
*Future* objects are used to bridge **low-level callback-based code**
with high-level async/await code.
Future Functions
================
.. function:: isfuture(obj)
Return ``True`` if *obj* is either of:
* an instance of :class:`asyncio.Future`,
* an instance of :class:`asyncio.Task`,
* a Future-like object with a ``_asyncio_future_blocking``
attribute.
.. versionadded:: 3.5
.. function:: ensure_future(obj, *, loop=None)
Return:
* *obj* argument as is, if *obj* is a :class:`Future`,
a :class:`Task`, or a Future-like object (:func:`isfuture`
is used for the test.)
* a :class:`Task` object wrapping *obj*, if *obj* is a
coroutine (:func:`iscoroutine` is used for the test);
in this case the coroutine will be scheduled by
``ensure_future()``.
* a :class:`Task` object that would await on *obj*, if *obj* is an
awaitable (:func:`inspect.isawaitable` is used for the test.)
If *obj* is neither of the above a :exc:`TypeError` is raised.
.. important::
Save a reference to the result of this function, to avoid
a task disappearing mid-execution.
See also the :func:`create_task` function which is the
preferred way for creating new tasks or use :class:`asyncio.TaskGroup`
which keeps reference to the task internally.
.. versionchanged:: 3.5.1
The function accepts any :term:`awaitable` object.
.. deprecated:: 3.10
Deprecation warning is emitted if *obj* is not a Future-like object
and *loop* is not specified and there is no running event loop.
.. function:: wrap_future(future, *, loop=None)
Wrap a :class:`concurrent.futures.Future` object in a
:class:`asyncio.Future` object.
.. deprecated:: 3.10
Deprecation warning is emitted if *future* is not a Future-like object
and *loop* is not specified and there is no running event loop.
Future Object
=============
.. class:: Future(*, loop=None)
A Future represents an eventual result of an asynchronous
operation. Not thread-safe.
Future is an :term:`awaitable` object. Coroutines can await on
Future objects until they either have a result or an exception
set, or until they are cancelled. A Future can be awaited multiple
times and the result is same.
Typically Futures are used to enable low-level
callback-based code (e.g. in protocols implemented using asyncio
:ref:`transports <asyncio-transports-protocols>`)
to interoperate with high-level async/await code.
The rule of thumb is to never expose Future objects in user-facing
APIs, and the recommended way to create a Future object is to call
:meth:`loop.create_future`. This way alternative event loop
implementations can inject their own optimized implementations
of a Future object.
.. versionchanged:: 3.7
Added support for the :mod:`contextvars` module.
.. deprecated:: 3.10
Deprecation warning is emitted if *loop* is not specified
and there is no running event loop.
.. method:: result()
Return the result of the Future.
If the Future is *done* and has a result set by the
:meth:`set_result` method, the result value is returned.
If the Future is *done* and has an exception set by the
:meth:`set_exception` method, this method raises the exception.
If the Future has been *cancelled*, this method raises
a :exc:`CancelledError` exception.
If the Future's result isn't yet available, this method raises
an :exc:`InvalidStateError` exception.
.. method:: set_result(result)
Mark the Future as *done* and set its result.
Raises an :exc:`InvalidStateError` error if the Future is
already *done*.
.. method:: set_exception(exception)
Mark the Future as *done* and set an exception.
Raises an :exc:`InvalidStateError` error if the Future is
already *done*.
.. method:: done()
Return ``True`` if the Future is *done*.
A Future is *done* if it was *cancelled* or if it has a result
or an exception set with :meth:`set_result` or
:meth:`set_exception` calls.
.. method:: cancelled()
Return ``True`` if the Future was *cancelled*.
The method is usually used to check if a Future is not
*cancelled* before setting a result or an exception for it::
if not fut.cancelled():
fut.set_result(42)
.. method:: add_done_callback(callback, *, context=None)
Add a callback to be run when the Future is *done*.
The *callback* is called with the Future object as its only
argument.
If the Future is already *done* when this method is called,
the callback is scheduled with :meth:`loop.call_soon`.
An optional keyword-only *context* argument allows specifying a
custom :class:`contextvars.Context` for the *callback* to run in.
The current context is used when no *context* is provided.
:func:`functools.partial` can be used to pass parameters
to the callback, e.g.::
# Call 'print("Future:", fut)' when "fut" is done.
fut.add_done_callback(
functools.partial(print, "Future:"))
.. versionchanged:: 3.7
The *context* keyword-only parameter was added.
See :pep:`567` for more details.
.. method:: remove_done_callback(callback)
Remove *callback* from the callbacks list.
Returns the number of callbacks removed, which is typically 1,
unless a callback was added more than once.
.. method:: cancel(msg=None)
Cancel the Future and schedule callbacks.
If the Future is already *done* or *cancelled*, return ``False``.
Otherwise, change the Future's state to *cancelled*,
schedule the callbacks, and return ``True``.
.. versionchanged:: 3.9
Added the *msg* parameter.
.. method:: exception()
Return the exception that was set on this Future.
The exception (or ``None`` if no exception was set) is
returned only if the Future is *done*.
If the Future has been *cancelled*, this method raises a
:exc:`CancelledError` exception.
If the Future isn't *done* yet, this method raises an
:exc:`InvalidStateError` exception.
.. method:: get_loop()
Return the event loop the Future object is bound to.
.. versionadded:: 3.7
.. _asyncio_example_future:
This example creates a Future object, creates and schedules an
asynchronous Task to set result for the Future, and waits until
the Future has a result::
async def set_after(fut, delay, value):
# Sleep for *delay* seconds.
await asyncio.sleep(delay)
# Set *value* as a result of *fut* Future.
fut.set_result(value)
async def main():
# Get the current event loop.
loop = asyncio.get_running_loop()
# Create a new Future object.
fut = loop.create_future()
# Run "set_after()" coroutine in a parallel Task.
# We are using the low-level "loop.create_task()" API here because
# we already have a reference to the event loop at hand.
# Otherwise we could have just used "asyncio.create_task()".
loop.create_task(
set_after(fut, 1, '... world'))
print('hello ...')
# Wait until *fut* has a result (1 second) and print it.
print(await fut)
asyncio.run(main())
.. important::
The Future object was designed to mimic
:class:`concurrent.futures.Future`. Key differences include:
- unlike asyncio Futures, :class:`concurrent.futures.Future`
instances cannot be awaited.
- :meth:`asyncio.Future.result` and :meth:`asyncio.Future.exception`
do not accept the *timeout* argument.
- :meth:`asyncio.Future.result` and :meth:`asyncio.Future.exception`
raise an :exc:`InvalidStateError` exception when the Future is not
*done*.
- Callbacks registered with :meth:`asyncio.Future.add_done_callback`
are not called immediately. They are scheduled with
:meth:`loop.call_soon` instead.
- asyncio Future is not compatible with the
:func:`concurrent.futures.wait` and
:func:`concurrent.futures.as_completed` functions.
- :meth:`asyncio.Future.cancel` accepts an optional ``msg`` argument,
but :meth:`concurrent.futures.Future.cancel` does not.
|