.. currentmodule:: asyncio
This section outlines high-level asyncio APIs to work with coroutines and Tasks.
Coroutines declared with async/await syntax is the preferred way of writing asyncio applications. For example, the following snippet of code (requires Python 3.7+) prints "hello", waits 1 second, and then prints "world":
>>> import asyncio
>>> async def main():
... print('hello')
... await asyncio.sleep(1)
... print('world')
>>> asyncio.run(main())
hello
world
Note that simply calling a coroutine will not schedule it to be executed:
>>> main() <coroutine object main at 0x1053bb7c8>
To actually run a coroutine, asyncio provides three main mechanisms:
The :func:`asyncio.run` function to run the top-level entry point "main()" function (see the above example.)
Awaiting on a coroutine. The following snippet of code will print "hello" after waiting for 1 second, and then print "world" after waiting for another 2 seconds:
import asyncio import time async def say_after(delay, what): await asyncio.sleep(delay) print(what) async def main(): print(f"started at {time.strftime('%X')}") await say_after(1, 'hello') await say_after(2, 'world') print(f"finished at {time.strftime('%X')}") asyncio.run(main())Expected output:
started at 17:13:52 hello world finished at 17:13:55
The :func:`asyncio.create_task` function to run coroutines concurrently as asyncio :class:`Tasks <Task>`.
Let's modify the above example and run two
say_aftercoroutines concurrently:async def main(): task1 = asyncio.create_task( say_after(1, 'hello')) task2 = asyncio.create_task( say_after(2, 'world')) print(f"started at {time.strftime('%X')}") # Wait until both tasks are completed (should take # around 2 seconds.) await task1 await task2 print(f"finished at {time.strftime('%X')}")Note that expected output now shows that the snippet runs 1 second faster than before:
started at 17:14:32 hello world finished at 17:14:34
We say that an object is an awaitable object if it can be used in an :keyword:`await` expression. Many asyncio APIs are designed to accept awaitables.
There are three main types of awaitable objects: coroutines, Tasks, and Futures.
Coroutines
Python coroutines are awaitables and therefore can be awaited from other coroutines:
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())
Important
In this documentation the term "coroutine" can be used for two closely related concepts:
- a coroutine function: an :keyword:`async def` function;
- a coroutine object: an object returned by calling a coroutine function.
asyncio also supports legacy :ref:`generator-based <asyncio_generator_based_coro>` coroutines.
Tasks
Tasks are used to schedule coroutines concurrently.
When a coroutine is wrapped into a Task with functions like :func:`asyncio.create_task` the coroutine is automatically scheduled to run soon:
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())
Futures
A :class:`Future` is a special low-level awaitable object that represents an eventual result of an asynchronous operation.
When a Future object is awaited it means that the coroutine will wait until the Future is resolved in some other place.
Future objects in asyncio are needed to allow callback-based code to be used with async/await.
Normally there is no need to create Future objects at the application level code.
Future objects, sometimes exposed by libraries and some asyncio APIs, can be awaited:
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()
)
A good example of a low-level function that returns a Future object is :meth:`loop.run_in_executor`.
.. function:: run(coro, \*, debug=False)
Execute the :term:`coroutine` *coro* and return the result.
This function runs the passed coroutine, taking care of
managing the asyncio event loop and *finalizing asynchronous
generators*.
This function cannot be called when another asyncio event loop is
running in the same thread.
If *debug* is ``True``, the event loop will be run in debug mode.
This function always creates a new event loop and closes it at
the end. It should be used as a main entry point for asyncio
programs, and should ideally only be called once.
Example::
async def main():
await asyncio.sleep(1)
print('hello')
asyncio.run(main())
.. versionadded:: 3.7
**Important:** this function has been added to asyncio in
Python 3.7 on a :term:`provisional basis <provisional api>`.
.. function:: create_task(coro)
Wrap the *coro* :ref:`coroutine <coroutine>` into a :class:`Task`
and schedule its execution. Return the Task object.
The task is executed in the loop returned by :func:`get_running_loop`,
:exc:`RuntimeError` is raised if there is no running loop in
current thread.
This function has been **added in Python 3.7**. Prior to
Python 3.7, the low-level :func:`asyncio.ensure_future` function
can be used instead::
async def coro():
...
# In Python 3.7+
task = asyncio.create_task(coro())
...
# This works in all Python versions but is less readable
task = asyncio.ensure_future(coro())
...
.. versionadded:: 3.7
.. coroutinefunction:: sleep(delay, result=None, \*, loop=None)
Block for *delay* seconds.
If *result* is provided, it is returned to the caller
when the coroutine completes.
``sleep()`` always suspends the current task, allowing other tasks
to run.
The *loop* argument is deprecated and scheduled for removal
in Python 3.10.
.. _asyncio_example_sleep:
Example of coroutine displaying the current date every second
for 5 seconds::
import asyncio
import datetime
async def display_date():
loop = asyncio.get_running_loop()
end_time = loop.time() + 5.0
while True:
print(datetime.datetime.now())
if (loop.time() + 1.0) >= end_time:
break
await asyncio.sleep(1)
asyncio.run(display_date())
.. awaitablefunction:: gather(\*aws, loop=None, return_exceptions=False)
Run :ref:`awaitable objects <asyncio-awaitables>` in the *aws*
sequence *concurrently*.
If any awaitable in *aws* is a coroutine, it is automatically
scheduled as a Task.
If all awaitables are completed successfully, the result is an
aggregate list of returned values. The order of result values
corresponds to the order of awaitables in *aws*.
If *return_exceptions* is ``False`` (default), the first
raised exception is immediately propagated to the task that
awaits on ``gather()``. Other awaitables in the *aws* sequence
**won't be cancelled** and will continue to run.
If *return_exceptions* is ``True``, exceptions are treated the
same as successful results, and aggregated in the result list.
If ``gather()`` is *cancelled*, all submitted awaitables
(that have not completed yet) are also *cancelled*.
If any Task or Future from the *aws* sequence is *cancelled*, it is
treated as if it raised :exc:`CancelledError` -- the ``gather()``
call is **not** cancelled in this case. This is to prevent the
cancellation of one submitted Task/Future to cause other
Tasks/Futures to be cancelled.
.. _asyncio_example_gather:
Example::
import asyncio
async def factorial(name, number):
f = 1
for i in range(2, number + 1):
print(f"Task {name}: Compute factorial({i})...")
await asyncio.sleep(1)
f *= i
print(f"Task {name}: factorial({number}) = {f}")
async def main():
# Schedule three calls *concurrently*:
await asyncio.gather(
factorial("A", 2),
factorial("B", 3),
factorial("C", 4),
)
asyncio.run(main())
# Expected output:
#
# Task A: Compute factorial(2)...
# Task B: Compute factorial(2)...
# Task C: Compute factorial(2)...
# Task A: factorial(2) = 2
# Task B: Compute factorial(3)...
# Task C: Compute factorial(3)...
# Task B: factorial(3) = 6
# Task C: Compute factorial(4)...
# Task C: factorial(4) = 24
.. versionchanged:: 3.7
If the *gather* itself is cancelled, the cancellation is
propagated regardless of *return_exceptions*.
.. awaitablefunction:: shield(aw, \*, loop=None)
Protect an :ref:`awaitable object <asyncio-awaitables>`
from being :meth:`cancelled <Task.cancel>`.
If *aw* is a coroutine it is automatically scheduled as a Task.
The statement::
res = await shield(something())
is equivalent to::
res = await something()
*except* that if the coroutine containing it is cancelled, the
Task running in ``something()`` is not cancelled. From the point
of view of ``something()``, the cancellation did not happen.
Although its caller is still cancelled, so the "await" expression
still raises a :exc:`CancelledError`.
If ``something()`` is cancelled by other means (i.e. from within
itself) that would also cancel ``shield()``.
If it is desired to completely ignore cancellation (not recommended)
the ``shield()`` function should be combined with a try/except
clause, as follows::
try:
res = await shield(something())
except CancelledError:
res = None
.. coroutinefunction:: wait_for(aw, timeout, \*, loop=None)
Wait for the *aw* :ref:`awaitable <asyncio-awaitables>`
to complete with a timeout.
If *aw* is a coroutine it is automatically scheduled as a Task.
*timeout* can either be ``None`` or a float or int number of seconds
to wait for. If *timeout* is ``None``, block until the future
completes.
If a timeout occurs, it cancels the task and raises
:exc:`asyncio.TimeoutError`.
To avoid the task :meth:`cancellation <Task.cancel>`,
wrap it in :func:`shield`.
The function will wait until the future is actually cancelled,
so the total wait time may exceed the *timeout*.
If the wait is cancelled, the future *aw* is also cancelled.
The *loop* argument is deprecated and scheduled for removal
in Python 3.10.
.. _asyncio_example_waitfor:
Example::
async def eternity():
# Sleep for one hour
await asyncio.sleep(3600)
print('yay!')
async def main():
# Wait for at most 1 second
try:
await asyncio.wait_for(eternity(), timeout=1.0)
except asyncio.TimeoutError:
print('timeout!')
asyncio.run(main())
# Expected output:
#
# timeout!
.. versionchanged:: 3.7
When *aw* is cancelled due to a timeout, ``wait_for`` waits
for *aw* to be cancelled. Previously, it raised
:exc:`asyncio.TimeoutError` immediately.
.. coroutinefunction:: wait(aws, \*, loop=None, timeout=None,\
return_when=ALL_COMPLETED)
Run :ref:`awaitable objects <asyncio-awaitables>` in the *aws*
set concurrently and block until the condition specified
by *return_when*.
If any awaitable in *aws* is a coroutine, it is automatically
scheduled as a Task. Passing coroutines objects to
``wait()`` directly is deprecated as it leads to
:ref:`confusing behavior <asyncio_example_wait_coroutine>`.
Returns two sets of Tasks/Futures: ``(done, pending)``.
Usage::
done, pending = await asyncio.wait(aws)
The *loop* argument is deprecated and scheduled for removal
in Python 3.10.
*timeout* (a float or int), if specified, can be used to control
the maximum number of seconds to wait before returning.
Note that this function does not raise :exc:`asyncio.TimeoutError`.
Futures or Tasks that aren't done when the timeout occurs are simply
returned in the second set.
*return_when* indicates when this function should return. It must
be one of the following constants:
.. tabularcolumns:: |l|L|
+-----------------------------+----------------------------------------+
| Constant | Description |
+=============================+========================================+
| :const:`FIRST_COMPLETED` | The function will return when any |
| | future finishes or is cancelled. |
+-----------------------------+----------------------------------------+
| :const:`FIRST_EXCEPTION` | The function will return when any |
| | future finishes by raising an |
| | exception. If no future raises an |
| | exception then it is equivalent to |
| | :const:`ALL_COMPLETED`. |
+-----------------------------+----------------------------------------+
| :const:`ALL_COMPLETED` | The function will return when all |
| | futures finish or are cancelled. |
+-----------------------------+----------------------------------------+
Unlike :func:`~asyncio.wait_for`, ``wait()`` does not cancel the
futures when a timeout occurs.
.. _asyncio_example_wait_coroutine:
.. note::
``wait()`` schedules coroutines as Tasks automatically and later
returns those implicitly created Task objects in ``(done, pending)``
sets. Therefore the following code won't work as expected::
async def foo():
return 42
coro = foo()
done, pending = await asyncio.wait({coro})
if coro in done:
# This branch will never be run!
Here is how the above snippet can be fixed::
async def foo():
return 42
task = asyncio.create_task(foo())
done, pending = await asyncio.wait({task})
if task in done:
# Everything will work as expected now.
Passing coroutine objects to ``wait()`` directly is
deprecated.
.. function:: as_completed(aws, \*, loop=None, timeout=None)
Run :ref:`awaitable objects <asyncio-awaitables>` in the *aws*
set concurrently. Return an iterator of :class:`Future` objects.
Each Future object returned represents the earliest result
from the set of the remaining awaitables.
Raises :exc:`asyncio.TimeoutError` if the timeout occurs before
all Futures are done.
Example::
for f in as_completed(aws):
earliest_result = await f
# ...
.. function:: run_coroutine_threadsafe(coro, loop)
Submit a coroutine to the given event loop. Thread-safe.
Return a :class:`concurrent.futures.Future` to wait for the result
from another OS thread.
This function is meant to be called from a different OS thread
than the one where the event loop is running. Example::
# Create a coroutine
coro = asyncio.sleep(1, result=3)
# Submit the coroutine to a given loop
future = asyncio.run_coroutine_threadsafe(coro, loop)
# Wait for the result with an optional timeout argument
assert future.result(timeout) == 3
If an exception is raised in the coroutine, the returned Future
will be notified. It can also be used to cancel the task in
the event loop::
try:
result = future.result(timeout)
except asyncio.TimeoutError:
print('The coroutine took too long, cancelling the task...')
future.cancel()
except Exception as exc:
print(f'The coroutine raised an exception: {exc!r}')
else:
print(f'The coroutine returned: {result!r}')
See the :ref:`concurrency and multithreading <asyncio-multithreading>`
section of the documentation.
Unlike other asyncio functions this function requires the *loop*
argument to be passed explicitly.
.. versionadded:: 3.5.1
.. function:: current_task(loop=None) Return the currently running :class:`Task` instance, or ``None`` if no task is running. If *loop* is ``None`` :func:`get_running_loop` is used to get the current loop. .. versionadded:: 3.7
.. function:: all_tasks(loop=None) Return a set of not yet finished :class:`Task` objects run by the loop. If *loop* is ``None``, :func:`get_running_loop` is used for getting current loop. .. versionadded:: 3.7
Note
Support for generator-based coroutines is deprecated and is scheduled for removal in Python 3.10.
Generator-based coroutines predate async/await syntax. They are
Python generators that use yield from expressions to await
on Futures and other coroutines.
Generator-based coroutines should be decorated with :func:`@asyncio.coroutine <asyncio.coroutine>`, although this is not enforced.
.. decorator:: coroutine
Decorator to mark generator-based coroutines.
This decorator enables legacy generator-based coroutines to be
compatible with async/await code::
@asyncio.coroutine
def old_style_coroutine():
yield from asyncio.sleep(1)
async def main():
await old_style_coroutine()
This decorator is **deprecated** and is scheduled for removal in
Python 3.10.
This decorator should not be used for :keyword:`async def`
coroutines.
.. function:: iscoroutine(obj) Return ``True`` if *obj* is a :ref:`coroutine object <coroutine>`. This method is different from :func:`inspect.iscoroutine` because it returns ``True`` for generator-based coroutines.
.. function:: iscoroutinefunction(func) Return ``True`` if *func* is a :ref:`coroutine function <coroutine>`. This method is different from :func:`inspect.iscoroutinefunction` because it returns ``True`` for generator-based coroutine functions decorated with :func:`@coroutine <coroutine>`.