diff options
Diffstat (limited to 'Doc/library/asyncio-task.rst')
-rw-r--r-- | Doc/library/asyncio-task.rst | 1022 |
1 files changed, 455 insertions, 567 deletions
diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 2b480d4be3..670e4a5fbe 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -1,97 +1,119 @@ .. currentmodule:: asyncio -Tasks and coroutines + +==================== +Coroutines and Tasks ==================== -**Source code:** :source:`Lib/asyncio/tasks.py` +This section outlines high-level asyncio APIs to work with coroutines +and Tasks. + +.. contents:: + :depth: 1 + :local: -**Source code:** :source:`Lib/asyncio/coroutines.py` .. _coroutine: Coroutines ----------- +========== -Coroutines used with :mod:`asyncio` may be implemented using the -:keyword:`async def` statement, or by using :term:`generators <generator>`. -The :keyword:`async def` type of coroutine was added in Python 3.5, and -is recommended if there is no need to support older Python versions. +Coroutines declared with async/await syntax is the preferred way of +writing asyncio applications. For example, the following snippet +of code prints "hello", waits 1 second, and then prints "world":: -Generator-based coroutines should be decorated with :func:`@asyncio.coroutine -<asyncio.coroutine>`, although this is not strictly enforced. -The decorator enables compatibility with :keyword:`async def` coroutines, -and also serves as documentation. Generator-based -coroutines use the ``yield from`` syntax introduced in :pep:`380`, -instead of the original ``yield`` syntax. + >>> import asyncio -The word "coroutine", like the word "generator", is used for two -different (though related) concepts: + >>> async def main(): + ... print('hello') + ... await asyncio.sleep(1) + ... print('world') -- The function that defines a coroutine - (a function definition using :keyword:`async def` or - decorated with ``@asyncio.coroutine``). If disambiguation is needed - we will call this a *coroutine function* (:func:`iscoroutinefunction` - returns ``True``). + >>> asyncio.run(main()) + hello + world -- The object obtained by calling a coroutine function. This object - represents a computation or an I/O operation (usually a combination) - that will complete eventually. If disambiguation is needed we will - call it a *coroutine object* (:func:`iscoroutine` returns ``True``). +Note that simply calling a coroutine will not schedule it to +be executed:: -Things a coroutine can do: + >>> main() + <coroutine object main at 0x1053bb7c8> -- ``result = await future`` or ``result = yield from future`` -- - suspends the coroutine until the - future is done, then returns the future's result, or raises an - exception, which will be propagated. (If the future is cancelled, - it will raise a ``CancelledError`` exception.) Note that tasks are - futures, and everything said about futures also applies to tasks. +To actually run a coroutine asyncio provides three main mechanisms: -- ``result = await coroutine`` or ``result = yield from coroutine`` -- - wait for another coroutine to - produce a result (or raise an exception, which will be propagated). - The ``coroutine`` expression must be a *call* to another coroutine. +* The :func:`asyncio.run` function to run the top-level + entry point "main()" function (see the above example.) -- ``return expression`` -- produce a result to the coroutine that is - waiting for this one using :keyword:`await` or ``yield from``. +* 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:: -- ``raise exception`` -- raise an exception in the coroutine that is - waiting for this one using :keyword:`await` or ``yield from``. + import asyncio + import time -Calling a coroutine does not start its code running -- -the coroutine object returned by the call doesn't do anything until you -schedule its execution. There are two basic ways to start it running: -call ``await coroutine`` or ``yield from coroutine`` from another coroutine -(assuming the other coroutine is already running!), or schedule its execution -using the :func:`ensure_future` function or the :meth:`AbstractEventLoop.create_task` -method. + async def say_after(delay, what): + await asyncio.sleep(delay) + print(what) + async def main(): + print('started at', time.strftime('%X')) -Coroutines (and tasks) can only run when the event loop is running. + await say_after(1, 'hello') + await say_after(2, 'world') -.. decorator:: coroutine + print('finished at', time.strftime('%X')) - Decorator to mark generator-based coroutines. This enables - the generator use :keyword:`!yield from` to call :keyword:`async - def` coroutines, and also enables the generator to be called by - :keyword:`async def` coroutines, for instance using an - :keyword:`await` expression. + asyncio.run(main()) - There is no need to decorate :keyword:`async def` coroutines themselves. + Expected output:: - If the generator is not yielded from before it is destroyed, an error - message is logged. See :ref:`Detect coroutines never scheduled - <asyncio-coroutine-not-scheduled>`. + started at 17:13:52 + hello + world + finished at 17:13:55 -.. note:: +* The :func:`asyncio.create_task` function to run coroutines + concurrently as asyncio :class:`Tasks <Task>`. + + Let's modify the above example and run two "set_after" coroutines + *concurrently*:: + + async def main(): + task1 = asyncio.create_task( + say_after(1, 'hello')) + + task2 = asyncio.create_task( + say_after(2, 'world')) + + print('started at', time.strftime('%X')) + + # Wait until both tasks are completed (should take + # around 2 seconds.) + await task1 + await task2 + + print('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 + +Note that in this documentation the term "coroutine" can be used for +two closely related concepts: + +* a *coroutine function*: an :keyword:`async def` function; - In this documentation, some methods are documented as coroutines, - even if they are plain Python functions returning a :class:`Future`. - This is intentional to have a freedom of tweaking the implementation - of these functions in the future. If such a function is needed to be - used in a callback-style code, wrap its result with :func:`ensure_future`. +* a *coroutine object*: object returned by calling a + *coroutine function*. +Running an asyncio Program +========================== + .. function:: run(coro, \*, debug=False) This function runs the passed coroutine, taking care of @@ -101,45 +123,46 @@ Coroutines (and tasks) can only run when the event loop is running. 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. + 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. .. versionadded:: 3.7 - **Important:** this has been been added to asyncio in Python 3.7 - on a :term:`provisional basis <provisional api>`. + **Important:** this function has been added to asyncio in + Python 3.7 on a :term:`provisional basis <provisional api>`. -.. _asyncio-hello-world-coroutine: +Creating Tasks +============== -Example: Hello World coroutine -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. function:: create_task(coro) -Example of coroutine displaying ``"Hello World"``:: + Wrap the *coro* :ref:`coroutine <coroutine>` into a task and schedule + its execution. Return the task object. - import asyncio + 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. - async def hello_world(): - print("Hello World!") + .. versionadded:: 3.7 - asyncio.run(hello_world()) -.. seealso:: +Sleeping +======== - The :ref:`Hello World with call_soon() <asyncio-hello-world-callback>` - example uses the :meth:`AbstractEventLoop.call_soon` method to schedule a - callback. +.. coroutinefunction:: sleep(delay, result=None, \*, loop=None) + Block for *delay* seconds. -.. _asyncio-date-coroutine: + If *result* is provided, it is returned to the caller + when the coroutine completes. -Example: Coroutine displaying the current date -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + .. _asyncio_example_sleep: -Example of coroutine displaying the current date every second during 5 seconds -using the :meth:`sleep` function:: + Example of coroutine displaying the current date every second + for 5 seconds:: import asyncio import datetime @@ -155,408 +178,283 @@ using the :meth:`sleep` function:: asyncio.run(display_date()) -.. seealso:: - - The :ref:`display the current date with call_later() - <asyncio-date-callback>` example uses a callback with the - :meth:`AbstractEventLoop.call_later` method. - - -Example: Chain coroutines -^^^^^^^^^^^^^^^^^^^^^^^^^ - -Example chaining coroutines:: - - import asyncio - - async def compute(x, y): - print("Compute %s + %s ..." % (x, y)) - await asyncio.sleep(1.0) - return x + y - - async def print_sum(x, y): - result = await compute(x, y) - print("%s + %s = %s" % (x, y, result)) - - loop = asyncio.get_event_loop() - loop.run_until_complete(print_sum(1, 2)) - loop.close() - -``compute()`` is chained to ``print_sum()``: ``print_sum()`` coroutine waits -until ``compute()`` is completed before returning its result. - -Sequence diagram of the example: - -.. image:: tulip_coro.png - :align: center - -The "Task" is created by the :meth:`AbstractEventLoop.run_until_complete` method -when it gets a coroutine object instead of a task. - -The diagram shows the control flow, it does not describe exactly how things -work internally. For example, the sleep coroutine creates an internal future -which uses :meth:`AbstractEventLoop.call_later` to wake up the task in 1 second. - - -InvalidStateError ------------------ - -.. exception:: InvalidStateError - - The operation is not allowed in this state. - - -TimeoutError ------------- - -.. exception:: TimeoutError - - The operation exceeded the given deadline. - -.. note:: - - This exception is different from the builtin :exc:`TimeoutError` exception! - - -Future ------- - -.. class:: Future(\*, loop=None) - - This class is *almost* compatible with :class:`concurrent.futures.Future`. - - Differences: - - - :meth:`result` and :meth:`exception` do not take a timeout argument and - raise an exception when the future isn't done yet. - - - Callbacks registered with :meth:`add_done_callback` are always called - via the event loop's :meth:`~AbstractEventLoop.call_soon`. - - - This class is not compatible with the :func:`~concurrent.futures.wait` and - :func:`~concurrent.futures.as_completed` functions in the - :mod:`concurrent.futures` package. - - This class is :ref:`not thread safe <asyncio-multithreading>`. - - .. method:: cancel() - - 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``. - - .. method:: cancelled() - - Return ``True`` if the future was cancelled. - - .. method:: done() - - Return ``True`` if the future is done. - - Done means either that a result / exception are available, or that the - future was cancelled. - - .. method:: result() - - Return the result this future represents. - - If the future has been cancelled, raises :exc:`CancelledError`. If the - future's result isn't yet available, raises :exc:`InvalidStateError`. If - the future is done and has an exception set, this exception is raised. - - .. 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, raises - :exc:`CancelledError`. If the future isn't done yet, raises - :exc:`InvalidStateError`. - .. method:: add_done_callback(callback, *, context=None) +Running Tasks Concurrently +========================== - Add a callback to be run when the future becomes done. +.. function:: gather(\*fs, loop=None, return_exceptions=False) - The *callback* is called with a single argument - the future object. If the - future is already done when this is called, the callback is scheduled - with :meth:`~AbstractEventLoop.call_soon`. + Return a Future aggregating results from the given coroutine objects, + Tasks, or Futures. - 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. + If all Tasks/Futures are completed successfully, the result is an + aggregate list of returned values. The result values are in the + order of the original *fs* sequence. - :ref:`Use functools.partial to pass parameters to the callback - <asyncio-pass-keywords>`. For example, - ``fut.add_done_callback(functools.partial(print, "Future:", - flush=True))`` will call ``print("Future:", fut, flush=True)``. + All coroutines in the *fs* list are automatically + scheduled as :class:`Tasks <Task>`. - .. versionchanged:: 3.7 - The *context* keyword-only parameter was added. See :pep:`567` - for more details. + If *return_exceptions* is ``True``, exceptions in the Tasks/Futures + are treated the same as successful results, and gathered in the + result list. Otherwise, the first raised exception is immediately + propagated to the returned Future. - .. method:: remove_done_callback(fn) + If the outer Future is *cancelled*, all submitted Tasks/Futures + (that have not completed yet) are also *cancelled*. - Remove all instances of a callback from the "call when done" list. + If any child is *cancelled*, it is treated as if it raised + :exc:`CancelledError` -- the outer Future 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. - Returns the number of callbacks removed. + All futures must share the same event loop. - .. method:: set_result(result) + .. versionchanged:: 3.7 + If the *gather* itself is cancelled, the cancellation is + propagated regardless of *return_exceptions*. - Mark the future done and set its result. + .. _asyncio_example_gather: - If the future is already done when this method is called, raises - :exc:`InvalidStateError`. + Example:: - .. method:: set_exception(exception) + import asyncio - Mark the future done and set an exception. + 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}") - If the future is already done when this method is called, raises - :exc:`InvalidStateError`. + async def main(): + await asyncio.gather( + factorial("A", 2), + factorial("B", 3), + factorial("C", 4), + )) - .. method:: get_loop() + asyncio.run(main()) - Return the event loop the future object is bound to. + # 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 - .. versionadded:: 3.7 +Shielding Tasks From Cancellation +================================= -Example: Future with run_until_complete() -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. coroutinefunction:: shield(fut, \*, loop=None) -Example combining a :class:`Future` and a :ref:`coroutine function -<coroutine>`:: + Wait for a Future/Task while protecting it from being cancelled. - import asyncio + *fut* can be a coroutine, a Task, or a Future-like object. If + *fut* is a coroutine it is automatically scheduled as a + :class:`Task`. - async def slow_operation(future): - await asyncio.sleep(1) - future.set_result('Future is done!') + The statement:: - loop = asyncio.get_event_loop() - future = asyncio.Future() - asyncio.ensure_future(slow_operation(future)) - loop.run_until_complete(future) - print(future.result()) - loop.close() + res = await shield(something()) -The coroutine function is responsible for the computation (which takes 1 second) -and it stores the result into the future. The -:meth:`~AbstractEventLoop.run_until_complete` method waits for the completion of -the future. + is equivalent to:: -.. note:: - The :meth:`~AbstractEventLoop.run_until_complete` method uses internally the - :meth:`~Future.add_done_callback` method to be notified when the future is - done. + 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`. -Example: Future with run_forever() -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + If ``something()`` is cancelled by other means (i.e. from within + itself) that would also cancel ``shield()``. -The previous example can be written differently using the -:meth:`Future.add_done_callback` method to describe explicitly the control -flow:: + If it is desired to completely ignore cancellation (not recommended) + the ``shield()`` function should be combined with a try/except + clause, as follows:: - import asyncio - - async def slow_operation(future): - await asyncio.sleep(1) - future.set_result('Future is done!') + try: + res = await shield(something()) + except CancelledError: + res = None - def got_result(future): - print(future.result()) - loop.stop() - loop = asyncio.get_event_loop() - future = asyncio.Future() - asyncio.ensure_future(slow_operation(future)) - future.add_done_callback(got_result) - try: - loop.run_forever() - finally: - loop.close() +Timeouts +======== -In this example, the future is used to link ``slow_operation()`` to -``got_result()``: when ``slow_operation()`` is done, ``got_result()`` is called -with the result. +.. coroutinefunction:: wait_for(fut, timeout, \*, loop=None) + Wait for a coroutine, Task, or Future to complete with timeout. -Task ----- + *fut* can be a coroutine, a Task, or a Future-like object. If + *fut* is a coroutine it is automatically scheduled as a + :class:`Task`. -.. function:: create_task(coro) + *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. - Wrap a :ref:`coroutine <coroutine>` *coro* into a task and schedule - its execution. Return the task object. + If a timeout occurs, it cancels the task and raises + :exc:`asyncio.TimeoutError`. - The task is executed in :func:`get_running_loop` context, - :exc:`RuntimeError` is raised if there is no running loop in - current thread. + To avoid the task cancellation, wrap it in :func:`shield`. - .. versionadded:: 3.7 + The function will wait until the future is actually cancelled, + so the total wait time may exceed the *timeout*. -.. class:: Task(coro, \*, loop=None) + If the wait is cancelled, the future *fut* is also cancelled. - A unit for concurrent running of :ref:`coroutines <coroutine>`, - subclass of :class:`Future`. + .. _asyncio_example_waitfor: - A task is responsible for executing a coroutine object in an event loop. If - the wrapped coroutine yields from a future, the task suspends the execution - of the wrapped coroutine and waits for the completion of the future. When - the future is done, the execution of the wrapped coroutine restarts with the - result or the exception of the future. + Example:: - Event loops use cooperative scheduling: an event loop only runs one task at - a time. Other tasks may run in parallel if other event loops are - running in different threads. While a task waits for the completion of a - future, the event loop executes a new task. + async def eternity(): + # Sleep for one hour + await asyncio.sleep(3600) + print('yay!') - The cancellation of a task is different from the cancellation of a - future. Calling :meth:`cancel` will throw a - :exc:`~concurrent.futures.CancelledError` to the wrapped - coroutine. :meth:`~Future.cancelled` only returns ``True`` if the - wrapped coroutine did not catch the - :exc:`~concurrent.futures.CancelledError` exception, or raised a - :exc:`~concurrent.futures.CancelledError` exception. + async def main(): + # Wait for at most 1 second + try: + await asyncio.wait_for(eternity(), timeout=1.0) + except asyncio.TimeoutError: + print('timeout!') - If a pending task is destroyed, the execution of its wrapped :ref:`coroutine - <coroutine>` did not complete. It is probably a bug and a warning is - logged: see :ref:`Pending task destroyed <asyncio-pending-task-destroyed>`. + asyncio.run(main()) - Don't directly create :class:`Task` instances: use the :func:`create_task` - function or the :meth:`AbstractEventLoop.create_task` method. + # Expected output: + # + # timeout! - Tasks support the :mod:`contextvars` module. When a Task - is created it copies the current context and later runs its coroutine - in the copied context. See :pep:`567` for more details. + .. versionchanged:: 3.7 + When *fut* is cancelled due to a timeout, ``wait_for`` waits + for *fut* to be cancelled. Previously, it raised + :exc:`asyncio.TimeoutError` immediately. - This class is :ref:`not thread safe <asyncio-multithreading>`. - .. versionchanged:: 3.7 - Added support for the :mod:`contextvars` module. +Waiting Primitives +================== - .. classmethod:: all_tasks(loop=None) +.. coroutinefunction:: wait(fs, \*, loop=None, timeout=None,\ + return_when=ALL_COMPLETED) - Return a set of all tasks for an event loop. + Wait for a set of coroutines, Tasks, or Futures to complete. - By default all tasks for the current event loop are returned. - If *loop* is ``None``, :func:`get_event_loop` function - is used to get the current loop. + *fs* is a list of coroutines, Futures, and/or Tasks. Coroutines + are automatically scheduled as :class:`Tasks <Task>`. - .. classmethod:: current_task(loop=None) + Returns two sets of Tasks/Futures: ``(done, pending)``. - Return the currently running task in an event loop or ``None``. + *timeout* (a float or int), if specified, can be used to control + the maximum number of seconds to wait before returning. - By default the current task for the current event loop is returned. + 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. - ``None`` is returned when called not in the context of a :class:`Task`. + *return_when* indicates when this function should return. It must + be one of the following constants: - .. method:: cancel() + .. tabularcolumns:: |l|L| - Request that this task cancel itself. + +-----------------------------+----------------------------------------+ + | 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. | + +-----------------------------+----------------------------------------+ - This arranges for a :exc:`~concurrent.futures.CancelledError` to be - thrown into the wrapped coroutine on the next cycle through the event - loop. The coroutine then has a chance to clean up or even deny the - request using try/except/finally. + Unlike :func:`~asyncio.wait_for`, ``wait()`` does not cancel the + futures when a timeout occurs. - Unlike :meth:`Future.cancel`, this does not guarantee that the task - will be cancelled: the exception might be caught and acted upon, delaying - cancellation of the task or preventing cancellation completely. The task - may also return a value or raise a different exception. + Usage:: - Immediately after this method is called, :meth:`~Future.cancelled` will - not return ``True`` (unless the task was already cancelled). A task will - be marked as cancelled when the wrapped coroutine terminates with a - :exc:`~concurrent.futures.CancelledError` exception (even if - :meth:`cancel` was not called). + done, pending = await asyncio.wait(fs) - .. method:: get_stack(\*, limit=None) - Return the list of stack frames for this task's coroutine. +.. function:: as_completed(fs, \*, loop=None, timeout=None) - If the coroutine is not done, this returns the stack where it is - suspended. If the coroutine has completed successfully or was - cancelled, this returns an empty list. If the coroutine was - terminated by an exception, this returns the list of traceback - frames. + Return an iterator of awaitables which return + :class:`Future` instances. - The frames are always ordered from oldest to newest. + Raises :exc:`asyncio.TimeoutError` if the timeout occurs before + all Futures are done. - The optional limit gives the maximum number of frames to return; by - default all available frames are returned. Its meaning differs depending - on whether a stack or a traceback is returned: the newest frames of a - stack are returned, but the oldest frames of a traceback are returned. - (This matches the behavior of the traceback module.) + Example:: - For reasons beyond our control, only one stack frame is returned for a - suspended coroutine. + for f in as_completed(fs): + result = await f + # ... - .. method:: print_stack(\*, limit=None, file=None) - Print the stack or traceback for this task's coroutine. +Scheduling From Other Threads +============================= - This produces output similar to that of the traceback module, for the - frames retrieved by get_stack(). The limit argument is passed to - get_stack(). The file argument is an I/O stream to which the output - is written; by default output is written to sys.stderr. +.. function:: run_coroutine_threadsafe(coro, loop) + Submit a coroutine to the given event loop. Thread-safe. -Example: Parallel execution of tasks -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Return a :class:`concurrent.futures.Future` to access the result. -Example executing 3 tasks (A, B, C) in parallel:: + This function is meant to be called from a different OS thread + than the one where the event loop is running. Example:: - import asyncio + # Create a coroutine + coro = asyncio.sleep(1, result=3) - async def factorial(name, number): - f = 1 - for i in range(2, number+1): - print("Task %s: Compute factorial(%s)..." % (name, i)) - await asyncio.sleep(1) - f *= i - print("Task %s: factorial(%s) = %s" % (name, number, f)) + # Submit the coroutine to a given loop + future = asyncio.run_coroutine_threadsafe(coro, loop) - loop = asyncio.get_event_loop() - loop.run_until_complete(asyncio.gather( - factorial("A", 2), - factorial("B", 3), - factorial("C", 4), - )) - loop.close() + # Wait for the result with an optional timeout argument + assert future.result(timeout) == 3 -Output:: + 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:: - 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 + try: + result = future.result(timeout) + except asyncio.TimeoutError: + print('The coroutine took too long, cancelling the task...') + future.cancel() + except Exception as exc: + print('The coroutine raised an exception: {!r}'.format(exc)) + else: + print('The coroutine returned: {!r}'.format(result)) -A task is automatically scheduled for execution when it is created. The event -loop stops when all tasks are done. + See the :ref:`concurrency and multithreading <asyncio-multithreading>` + section of the documentation. + Unlike other asyncio functions this functions requires the *loop* + argument to be passed explicitly. -Task functions --------------- + .. versionadded:: 3.5.1 -.. note:: - In the functions below, the optional *loop* argument allows explicitly setting - the event loop object used by the underlying task or coroutine. If it's - not provided, the default event loop is used. +Introspection +============= .. function:: current_task(loop=None) - Return the current running :class:`Task` instance or ``None``, if + 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 @@ -567,246 +465,236 @@ Task functions .. function:: all_tasks(loop=None) - Return a set of :class:`Task` objects created for the loop. + 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 (contrary to the deprecated :meth:`Task.all_tasks` method - that uses :func:`get_event_loop`.) + current loop. .. versionadded:: 3.7 -.. function:: as_completed(fs, \*, loop=None, timeout=None) - - Return an iterator whose values, when waited for, are :class:`Future` - instances. +Task Object +=========== - Raises :exc:`asyncio.TimeoutError` if the timeout occurs before all Futures - are done. - - Example:: - - for f in as_completed(fs): - result = await f # The 'await' may raise - # Use result - - .. note:: - - The futures ``f`` are not necessarily members of fs. +.. class:: Task(coro, \*, loop=None) -.. function:: ensure_future(coro_or_future, \*, loop=None) + A :class:`Future`-like object that wraps a Python + :ref:`coroutine <coroutine>`. Not thread-safe. - Schedule the execution of a :ref:`coroutine object <coroutine>`: wrap it in - a future. Return a :class:`Task` object. + Tasks are used to run coroutines in event loops. + If a coroutine awaits on a Future, the Task suspends + the execution of the coroutine and waits for the completion + of the Future. When the Future is *done*, the execution of + the wrapped coroutine resumes. - If the argument is a :class:`Future`, it is returned directly. + Event loops use cooperative scheduling: an event loop runs + one Task at a time. While a Task awaits for the completion of a + Future, the event loop runs other Tasks, callbacks, or performs + IO operations. - .. versionadded:: 3.4.4 + Use the high-level :func:`asyncio.create_task` function to create + Tasks, or the low-level :meth:`loop.create_task` or + :func:`ensure_future` functions. Manual instantiation of Tasks + is discouraged. - .. versionchanged:: 3.5.1 - The function accepts any :term:`awaitable` object. + To cancel a running Task use the :meth:`cancel` method. Calling it + will cause the Task to throw a :exc:`CancelledError` exception into + the wrapped coroutine. If a coroutine is awaiting on a Future + object during cancellation, the Future object will be cancelled. - .. note:: + :meth:`cancelled` can be used to check if the Task was cancelled. + The method returns ``True`` if the wrapped coroutine did not + suppress the :exc:`CancelledError` exception and was actually + cancelled. - :func:`create_task` (added in Python 3.7) is the preferable way - for spawning new tasks. + :class:`asyncio.Task` inherits from :class:`Future` all of its + APIs except :meth:`Future.set_result` and + :meth:`Future.set_exception`. - .. seealso:: + Tasks support the :mod:`contextvars` module. When a Task + is created it copies the current context and later runs its + coroutine in the copied context. - The :func:`create_task` function and - :meth:`AbstractEventLoop.create_task` method. + .. versionchanged:: 3.7 + Added support for the :mod:`contextvars` module. -.. function:: wrap_future(future, \*, loop=None) + .. method:: cancel() - Wrap a :class:`concurrent.futures.Future` object in a :class:`Future` - object. + Request the Task to be cancelled. -.. function:: gather(\*coros_or_futures, loop=None, return_exceptions=False) + This arranges for a :exc:`CancelledError` exception to be thrown + into the wrapped coroutine on the next cycle of the event loop. - Return a future aggregating results from the given coroutine objects or - futures. + The coroutine then has a chance to clean up or even deny the + request by suppressing the exception with a :keyword:`try` ... + ... ``except CancelledError`` ... :keyword:`finally` block. + Therefore, unlike :meth:`Future.cancel`, :meth:`Task.cancel` does + not guarantee that the Task will be cancelled, although + suppressing cancellation completely is not common and is actively + discouraged. - All futures must share the same event loop. If all the tasks are done - successfully, the returned future's result is the list of results (in the - order of the original sequence, not necessarily the order of results - arrival). If *return_exceptions* is true, exceptions in the tasks are - treated the same as successful results, and gathered in the result list; - otherwise, the first raised exception will be immediately propagated to the - returned future. + .. _asyncio_example_task_cancel: - Cancellation: if the outer Future is cancelled, all children (that have not - completed yet) are also cancelled. If any child is cancelled, this is - treated as if it raised :exc:`~concurrent.futures.CancelledError` -- the - outer Future is *not* cancelled in this case. (This is to prevent the - cancellation of one child to cause other children to be cancelled.) + The following example illustrates how coroutines can intercept + the cancellation request:: - .. versionchanged:: 3.7.0 - If the *gather* itself is cancelled, the cancellation is propagated - regardless of *return_exceptions*. + async def cancel_me(): + print('cancel_me(): before sleep') -.. function:: iscoroutine(obj) + try: + # Wait for 1 hour + await asyncio.sleep(3600) + except asyncio.CancelledError: + print('cancel_me(): cancel sleep') + raise + finally: + print('cancel_me(): after sleep') - Return ``True`` if *obj* is a :ref:`coroutine object <coroutine>`, - which may be based on a generator or an :keyword:`async def` coroutine. + async def main(): + # Create a "cancel_me" Task + task = asyncio.create_task(cancel_me()) -.. function:: iscoroutinefunction(func) + # Wait for 1 second + await asyncio.sleep(1) - Return ``True`` if *func* is determined to be a :ref:`coroutine function - <coroutine>`, which may be a decorated generator function or an - :keyword:`async def` function. + task.cancel() + try: + await task + except asyncio.CancelledError: + print("main(): cancel_me is cancelled now") -.. function:: run_coroutine_threadsafe(coro, loop) + asyncio.run(main()) - Submit a :ref:`coroutine object <coroutine>` to a given event loop. + # Expected output: + # + # cancel_me(): before sleep + # cancel_me(): cancel sleep + # cancel_me(): after sleep + # main(): cancel_me is cancelled now - Return a :class:`concurrent.futures.Future` to access the result. + .. method:: cancelled() - This function is meant to be called from a different thread than the one - where the event loop is running. Usage:: + Return ``True`` if the Task is *cancelled*. - # 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 + The Task is *cancelled* when the cancellation was requested with + :meth:`cancel` and the wrapped coroutine propagated the + :exc:`CancelledError` exception thrown into it. - 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:: + .. method:: done() - try: - result = future.result(timeout) - except asyncio.TimeoutError: - print('The coroutine took too long, cancelling the task...') - future.cancel() - except Exception as exc: - print('The coroutine raised an exception: {!r}'.format(exc)) - else: - print('The coroutine returned: {!r}'.format(result)) + Return ``True`` if the Task is *done*. - See the :ref:`concurrency and multithreading <asyncio-multithreading>` - section of the documentation. + A Task is *done* when the wrapped coroutine either returned + a value, raised an exception, or the Task was cancelled. - .. note:: + .. method:: get_stack(\*, limit=None) - Unlike other functions from the module, - :func:`run_coroutine_threadsafe` requires the *loop* argument to - be passed explicitly. + Return the list of stack frames for this Task. - .. versionadded:: 3.5.1 + If the wrapped coroutine is not done, this returns the stack + where it is suspended. If the coroutine has completed + successfully or was cancelled, this returns an empty list. + If the coroutine was terminated by an exception, this returns + the list of traceback frames. -.. coroutinefunction:: sleep(delay, result=None, \*, loop=None) + The frames are always ordered from oldest to newest. - Create a :ref:`coroutine <coroutine>` that completes after a given - time (in seconds). If *result* is provided, it is produced to the caller - when the coroutine completes. + Only one stack frame is returned for a suspended coroutine. - The resolution of the sleep depends on the :ref:`granularity of the event - loop <asyncio-delayed-calls>`. + The optional *limit* argument sets the maximum number of frames + to return; by default all available frames are returned. + The ordering of the returned list differs depending on whether + a stack or a traceback is returned: the newest frames of a + stack are returned, but the oldest frames of a traceback are + returned. (This matches the behavior of the traceback module.) - This function is a :ref:`coroutine <coroutine>`. + .. method:: print_stack(\*, limit=None, file=None) -.. coroutinefunction:: shield(arg, \*, loop=None) + Print the stack or traceback for this Task. - Wait for a future, shielding it from cancellation. + This produces output similar to that of the traceback module + for the frames retrieved by :meth:`get_stack`. - The statement:: + The *limit* argument is passed to :meth:`get_stack` directly. - res = await shield(something()) + The *file* argument is an I/O stream to which the output + is written; by default output is written to :data:`sys.stderr`. - is exactly equivalent to the statement:: + .. classmethod:: all_tasks(loop=None) - res = await something() + Return a set of all tasks for an event loop. - *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. But its caller is still - cancelled, so the yield-from expression still raises - :exc:`~concurrent.futures.CancelledError`. Note: If ``something()`` is - cancelled by other means this will still cancel ``shield()``. + By default all tasks for the current event loop are returned. + If *loop* is ``None``, the :func:`get_event_loop` function + is used to get the current loop. - If you want to completely ignore cancellation (not recommended) you can - combine ``shield()`` with a try/except clause, as follows:: + This method is **deprecated** and will be removed in + Python 3.9. Use the :func:`all_tasks` function instead. - try: - res = await shield(something()) - except CancelledError: - res = None + .. classmethod:: current_task(loop=None) + Return the currently running task or ``None``. -.. coroutinefunction:: wait(futures, \*, loop=None, timeout=None,\ - return_when=ALL_COMPLETED) + If *loop* is ``None``, the :func:`get_event_loop` function + is used to get the current loop. - Wait for the Futures and coroutine objects given by the sequence *futures* - to complete. Coroutines will be wrapped in Tasks. Returns two sets of - :class:`Future`: (done, pending). + This method is **deprecated** and will be removed in + Python 3.9. Use the :func:`current_task` function instead. - The sequence *futures* must not be empty. - *timeout* can be used to control the maximum number of seconds to wait before - returning. *timeout* can be an int or float. If *timeout* is not specified - or ``None``, there is no limit to the wait time. +.. _asyncio_generator_based_coro: - *return_when* indicates when this function should return. It must be one of - the following constants of the :mod:`concurrent.futures` module: +Generator-based Coroutines +========================== - .. tabularcolumns:: |l|L| +.. note:: - +-----------------------------+----------------------------------------+ - | 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. | - +-----------------------------+----------------------------------------+ + Support for generator-based coroutines is **deprecated** and + is scheduled for removal in Python 4.0. - Unlike :func:`~asyncio.wait_for`, ``wait()`` will not cancel the futures - when a timeout occurs. +Generator-based coroutines predate async/await syntax. They are +Python generators that use ``yield from`` expressions to await +on Futures and other coroutines. - This function is a :ref:`coroutine <coroutine>`. +Generator-based coroutines should be decorated with +:func:`@asyncio.coroutine <asyncio.coroutine>`, although this is not +enforced. - Usage:: - done, pending = await asyncio.wait(fs) +.. decorator:: coroutine - .. note:: + Decorator to mark generator-based coroutines. - This does not raise :exc:`asyncio.TimeoutError`! Futures that aren't done - when the timeout occurs are returned in the second set. + 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) -.. coroutinefunction:: wait_for(fut, timeout, \*, loop=None) + async def main(): + await old_style_coroutine() - Wait for the single :class:`Future` or :ref:`coroutine object <coroutine>` - to complete with timeout. If *timeout* is ``None``, block until the future - completes. + This decorator is **deprecated** and is scheduled for removal in + Python 4.0. - Coroutine will be wrapped in :class:`Task`. + This decorator should not be used for :keyword:`async def` + coroutines. - Returns result of the Future or coroutine. When a timeout occurs, it - cancels the task and raises :exc:`asyncio.TimeoutError`. To avoid the task - cancellation, wrap it in :func:`shield`. The function will wait until - the future is actually cancelled, so the total wait time may exceed - the *timeout*. +.. function:: iscoroutine(obj) - If the wait is cancelled, the future *fut* is also cancelled. + Return ``True`` if *obj* is a :ref:`coroutine object <coroutine>`. - This function is a :ref:`coroutine <coroutine>`, usage:: + This method is different from :func:`inspect.iscoroutine` because + it returns ``True`` for generator-based coroutines decorated with + :func:`@coroutine <coroutine>`. - result = await asyncio.wait_for(fut, 60.0) +.. function:: iscoroutinefunction(func) - .. versionchanged:: 3.4.3 - If the wait is cancelled, the future *fut* is now also cancelled. + Return ``True`` if *func* is a :ref:`coroutine function + <coroutine>`. - .. versionchanged:: 3.7 - When *fut* is cancelled due to a timeout, ``wait_for`` now waits - for *fut* to be cancelled. Previously, - it raised :exc:`~asyncio.TimeoutError` immediately. + This method is different from :func:`inspect.iscoroutinefunction` + because it returns ``True`` for generator-based coroutine functions + decorated with :func:`@coroutine <coroutine>`. |