diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2014-07-08 10:39:10 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2014-07-08 10:39:10 (GMT) |
commit | 530ef2f0693d50435a8d62ea84d3fdcbe662d8aa (patch) | |
tree | 2aa2c368fab19c3353e9c1e282d46c1596ee4af4 /Doc/library/asyncio-dev.rst | |
parent | 896a25ab30269369201401b50c66130911dd2238 (diff) | |
download | cpython-530ef2f0693d50435a8d62ea84d3fdcbe662d8aa.zip cpython-530ef2f0693d50435a8d62ea84d3fdcbe662d8aa.tar.gz cpython-530ef2f0693d50435a8d62ea84d3fdcbe662d8aa.tar.bz2 |
Update asyncio documentation
- Document the new create_task() method
- "Hide" the Task class: point to the create_task() method for interoperability
- Rewrite the documentation of the Task class
- Document the "Pending task destroyed"
- Update output in debug mode of examples in the dev section
- Replace Task() with create_task() in examples
Diffstat (limited to 'Doc/library/asyncio-dev.rst')
-rw-r--r-- | Doc/library/asyncio-dev.rst | 95 |
1 files changed, 66 insertions, 29 deletions
diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst index 2b3ad94..bf68121 100644 --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -103,20 +103,11 @@ the logger ``'asyncio'``. Detect coroutine objects never scheduled ---------------------------------------- -When a coroutine function is called but not passed to :func:`async` or to the -:class:`Task` constructor, it is not scheduled and it is probably a bug. - -To detect such bug, :ref:`enable the debug mode of asyncio -<asyncio-debug-mode>`. When the coroutine object is destroyed by the garbage -collector, a log will be emitted with the traceback where the coroutine -function was called. See the :ref:`asyncio logger <asyncio-logger>`. - -The debug flag changes the behaviour of the :func:`coroutine` decorator. The -debug flag value is only used when then coroutine function is defined, not when -it is called. Coroutine functions defined before the debug flag is set to -``True`` will not be tracked. For example, it is not possible to debug -coroutines defined in the :mod:`asyncio` module, because the module must be -imported before the flag value can be changed. +When a coroutine function is called and its result is not passed to +:func:`async` or to the :meth:`BaseEventLoop.create_task` method: the execution +of the coroutine objet will never be scheduled and it is probably a bug. +:ref:`Enable the debug mode of asyncio <asyncio-debug-mode>` to :ref:`log a +warning <asyncio-logger>` to detect it. Example with the bug:: @@ -130,20 +121,27 @@ Example with the bug:: Output in debug mode:: - Coroutine 'test' defined at test.py:4 was never yielded from + Coroutine test() at test.py:3 was never yielded from + Coroutine object created at (most recent call last): + File "test.py", line 7, in <module> + test() -The fix is to call the :func:`async` function or create a :class:`Task` object -with this coroutine object. +The fix is to call the :func:`async` function or the +:meth:`BaseEventLoop.create_task` method with the coroutine object. +.. seealso:: + + :ref:`Pending task destroyed <asyncio-pending-task-destroyed>`. -Detect exceptions not consumed ------------------------------- + +Detect exceptions never consumed +-------------------------------- Python usually calls :func:`sys.displayhook` on unhandled exceptions. If -:meth:`Future.set_exception` is called, but the exception is not consumed, -:func:`sys.displayhook` is not called. Instead, a log is emitted when the -future is deleted by the garbage collector, with the traceback where the -exception was raised. See the :ref:`asyncio logger <asyncio-logger>`. +:meth:`Future.set_exception` is called, but the exception is never consumed, +:func:`sys.displayhook` is not called. Instead, a :ref:`a log is emitted +<asyncio-logger>` when the future is deleted by the garbage collector, with the +traceback where the exception was raised. Example of unhandled exception:: @@ -159,16 +157,27 @@ Example of unhandled exception:: Output:: - Future/Task exception was never retrieved: + Task exception was never retrieved + future: <Task finished bug() done at asyncio/coroutines.py:139 exception=Exception('not consumed',)> + source_traceback: Object created at (most recent call last): + File "test.py", line 10, in <module> + asyncio.async(bug()) + File "asyncio/tasks.py", line 510, in async + task = loop.create_task(coro_or_future) Traceback (most recent call last): - File "/usr/lib/python3.4/asyncio/tasks.py", line 279, in _step + File "asyncio/tasks.py", line 244, in _step result = next(coro) - File "/usr/lib/python3.4/asyncio/tasks.py", line 80, in coro + File "coroutines.py", line 78, in __next__ + return next(self.gen) + File "asyncio/coroutines.py", line 141, in coro res = func(*args, **kw) - File "test.py", line 5, in bug + File "test.py", line 7, in bug raise Exception("not consumed") Exception: not consumed +:ref:`Enable the debug mode of asyncio <asyncio-debug-mode>` to get the +traceback where the task was created. + There are different options to fix this issue. The first option is to chain to coroutine in another coroutine and use classic try/except:: @@ -195,7 +204,7 @@ function:: See also the :meth:`Future.exception` method. -Chain coroutines correctly +Chain correctly coroutines -------------------------- When a coroutine function calls other coroutine functions and tasks, they @@ -246,7 +255,9 @@ Actual output:: (3) close file (2) write into file - Pending tasks at exit: {Task(<create>)<PENDING>} + Pending tasks at exit: {<Task pending create() at test.py:7 wait_for=<Future pending cb=[Task._wakeup()]>>} + Task was destroyed but it is pending! + task: <Task pending create() done at test.py:5 wait_for=<Future pending cb=[Task._wakeup()]>> The loop stopped before the ``create()`` finished, ``close()`` has been called before ``write()``, whereas coroutine functions were called in this order: @@ -272,3 +283,29 @@ Or without ``asyncio.async()``:: yield from asyncio.sleep(2.0) loop.stop() + +.. _asyncio-pending-task-destroyed: + +Pending task destroyed +---------------------- + +If a pending task is destroyed, the execution of its wrapped :ref:`coroutine +<coroutine>` did not complete. It is probably a bug and so a warning is logged. + +Example of log:: + + Task was destroyed but it is pending! + source_traceback: Object created at (most recent call last): + File "test.py", line 17, in <module> + task = asyncio.async(coro, loop=loop) + File "asyncio/tasks.py", line 510, in async + task = loop.create_task(coro_or_future) + task: <Task pending kill_me() done at test.py:5 wait_for=<Future pending cb=[Task._wakeup()]>> + +:ref:`Enable the debug mode of asyncio <asyncio-debug-mode>` to get the +traceback where the task was created. + +.. seealso:: + + :ref:`Detect coroutine objects never scheduled <asyncio-coroutine-not-scheduled>`. + |