Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 530ef2f

Browse files
committed
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
1 parent 896a25a commit 530ef2f

4 files changed

Lines changed: 131 additions & 49 deletions

File tree

Doc/library/asyncio-dev.rst

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -103,20 +103,11 @@ the logger ``'asyncio'``.
103103
Detect coroutine objects never scheduled
104104
----------------------------------------
105105

106-
When a coroutine function is called but not passed to :func:`async` or to the
107-
:class:`Task` constructor, it is not scheduled and it is probably a bug.
108-
109-
To detect such bug, :ref:`enable the debug mode of asyncio
110-
<asyncio-debug-mode>`. When the coroutine object is destroyed by the garbage
111-
collector, a log will be emitted with the traceback where the coroutine
112-
function was called. See the :ref:`asyncio logger <asyncio-logger>`.
113-
114-
The debug flag changes the behaviour of the :func:`coroutine` decorator. The
115-
debug flag value is only used when then coroutine function is defined, not when
116-
it is called. Coroutine functions defined before the debug flag is set to
117-
``True`` will not be tracked. For example, it is not possible to debug
118-
coroutines defined in the :mod:`asyncio` module, because the module must be
119-
imported before the flag value can be changed.
106+
When a coroutine function is called and its result is not passed to
107+
:func:`async` or to the :meth:`BaseEventLoop.create_task` method: the execution
108+
of the coroutine objet will never be scheduled and it is probably a bug.
109+
:ref:`Enable the debug mode of asyncio <asyncio-debug-mode>` to :ref:`log a
110+
warning <asyncio-logger>` to detect it.
120111

121112
Example with the bug::
122113

@@ -130,20 +121,27 @@ Example with the bug::
130121

131122
Output in debug mode::
132123

133-
Coroutine 'test' defined at test.py:4 was never yielded from
124+
Coroutine test() at test.py:3 was never yielded from
125+
Coroutine object created at (most recent call last):
126+
File "test.py", line 7, in <module>
127+
test()
134128

135-
The fix is to call the :func:`async` function or create a :class:`Task` object
136-
with this coroutine object.
129+
The fix is to call the :func:`async` function or the
130+
:meth:`BaseEventLoop.create_task` method with the coroutine object.
137131

132+
.. seealso::
133+
134+
:ref:`Pending task destroyed <asyncio-pending-task-destroyed>`.
138135

139-
Detect exceptions not consumed
140-
------------------------------
136+
137+
Detect exceptions never consumed
138+
--------------------------------
141139

142140
Python usually calls :func:`sys.displayhook` on unhandled exceptions. If
143-
:meth:`Future.set_exception` is called, but the exception is not consumed,
144-
:func:`sys.displayhook` is not called. Instead, a log is emitted when the
145-
future is deleted by the garbage collector, with the traceback where the
146-
exception was raised. See the :ref:`asyncio logger <asyncio-logger>`.
141+
:meth:`Future.set_exception` is called, but the exception is never consumed,
142+
:func:`sys.displayhook` is not called. Instead, a :ref:`a log is emitted
143+
<asyncio-logger>` when the future is deleted by the garbage collector, with the
144+
traceback where the exception was raised.
147145

148146
Example of unhandled exception::
149147

@@ -159,16 +157,27 @@ Example of unhandled exception::
159157

160158
Output::
161159

162-
Future/Task exception was never retrieved:
160+
Task exception was never retrieved
161+
future: <Task finished bug() done at asyncio/coroutines.py:139 exception=Exception('not consumed',)>
162+
source_traceback: Object created at (most recent call last):
163+
File "test.py", line 10, in <module>
164+
asyncio.async(bug())
165+
File "asyncio/tasks.py", line 510, in async
166+
task = loop.create_task(coro_or_future)
163167
Traceback (most recent call last):
164-
File "/usr/lib/python3.4/asyncio/tasks.py", line 279, in _step
168+
File "asyncio/tasks.py", line 244, in _step
165169
result = next(coro)
166-
File "/usr/lib/python3.4/asyncio/tasks.py", line 80, in coro
170+
File "coroutines.py", line 78, in __next__
171+
return next(self.gen)
172+
File "asyncio/coroutines.py", line 141, in coro
167173
res = func(*args, **kw)
168-
File "test.py", line 5, in bug
174+
File "test.py", line 7, in bug
169175
raise Exception("not consumed")
170176
Exception: not consumed
171177

178+
:ref:`Enable the debug mode of asyncio <asyncio-debug-mode>` to get the
179+
traceback where the task was created.
180+
172181
There are different options to fix this issue. The first option is to chain to
173182
coroutine in another coroutine and use classic try/except::
174183

@@ -195,7 +204,7 @@ function::
195204
See also the :meth:`Future.exception` method.
196205

197206

198-
Chain coroutines correctly
207+
Chain correctly coroutines
199208
--------------------------
200209

201210
When a coroutine function calls other coroutine functions and tasks, they
@@ -246,7 +255,9 @@ Actual output::
246255

247256
(3) close file
248257
(2) write into file
249-
Pending tasks at exit: {Task(<create>)<PENDING>}
258+
Pending tasks at exit: {<Task pending create() at test.py:7 wait_for=<Future pending cb=[Task._wakeup()]>>}
259+
Task was destroyed but it is pending!
260+
task: <Task pending create() done at test.py:5 wait_for=<Future pending cb=[Task._wakeup()]>>
250261

251262
The loop stopped before the ``create()`` finished, ``close()`` has been called
252263
before ``write()``, whereas coroutine functions were called in this order:
@@ -272,3 +283,29 @@ Or without ``asyncio.async()``::
272283
yield from asyncio.sleep(2.0)
273284
loop.stop()
274285

286+
287+
.. _asyncio-pending-task-destroyed:
288+
289+
Pending task destroyed
290+
----------------------
291+
292+
If a pending task is destroyed, the execution of its wrapped :ref:`coroutine
293+
<coroutine>` did not complete. It is probably a bug and so a warning is logged.
294+
295+
Example of log::
296+
297+
Task was destroyed but it is pending!
298+
source_traceback: Object created at (most recent call last):
299+
File "test.py", line 17, in <module>
300+
task = asyncio.async(coro, loop=loop)
301+
File "asyncio/tasks.py", line 510, in async
302+
task = loop.create_task(coro_or_future)
303+
task: <Task pending kill_me() done at test.py:5 wait_for=<Future pending cb=[Task._wakeup()]>>
304+
305+
:ref:`Enable the debug mode of asyncio <asyncio-debug-mode>` to get the
306+
traceback where the task was created.
307+
308+
.. seealso::
309+
310+
:ref:`Detect coroutine objects never scheduled <asyncio-coroutine-not-scheduled>`.
311+

Doc/library/asyncio-eventloop.rst

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ Run an event loop
102102

103103
Run until the :class:`Future` is done.
104104

105-
If the argument is a :ref:`coroutine <coroutine>`, it is wrapped
106-
in a :class:`Task`.
105+
If the argument is a :ref:`coroutine object <coroutine>`, it is wrapped by
106+
:func:`async`.
107107

108108
Return the Future's result, or raise its exception.
109109

@@ -205,6 +205,25 @@ a different clock than :func:`time.time`.
205205
The :func:`asyncio.sleep` function.
206206

207207

208+
Coroutines
209+
----------
210+
211+
.. method:: BaseEventLoop.create_task(coro)
212+
213+
Schedule the execution of a :ref:`coroutine object <coroutine>`: wrap it in
214+
a future. Return a :class:`Task` object.
215+
216+
Third-party event loops can use their own subclass of :class:`Task` for
217+
interoperability. In this case, the result type is a subclass of
218+
:class:`Task`.
219+
220+
.. seealso::
221+
222+
The :meth:`async` function.
223+
224+
.. versionadded:: 3.4.2
225+
226+
208227
Creating connections
209228
--------------------
210229

Doc/library/asyncio-stream.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ Stream functions
4141
:class:`StreamReader` object, while *client_writer* is a
4242
:class:`StreamWriter` object. This parameter can either be a plain callback
4343
function or a :ref:`coroutine function <coroutine>`; if it is a coroutine
44-
function, it will be automatically converted into a :class:`Task`.
44+
function, it will be automatically wrapped in a future using the
45+
:meth:`BaseEventLoop.create_task` method.
4546

4647
The rest of the arguments are all the usual arguments to
4748
:meth:`~BaseEventLoop.create_server()` except *protocol_factory*; most

Doc/library/asyncio-task.rst

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ generator, and the coroutine object returned by the call is really a
5151
generator object, which doesn't do anything until you iterate over it.
5252
In the case of a coroutine object, there are two basic ways to start
5353
it running: call ``yield from coroutine`` from another coroutine
54-
(assuming the other coroutine is already running!), or convert it to a
55-
:class:`Task`.
54+
(assuming the other coroutine is already running!), or schedule its execution
55+
using the :meth:`BaseEventLoop.create_task` method.
5656

5757
Coroutines (and tasks) can only run when the event loop is running.
5858

@@ -256,7 +256,7 @@ Example combining a :class:`Future` and a :ref:`coroutine function
256256

257257
loop = asyncio.get_event_loop()
258258
future = asyncio.Future()
259-
asyncio.Task(slow_operation(future))
259+
loop.create_task(slow_operation(future))
260260
loop.run_until_complete(future)
261261
print(future.result())
262262
loop.close()
@@ -292,7 +292,7 @@ flow::
292292

293293
loop = asyncio.get_event_loop()
294294
future = asyncio.Future()
295-
asyncio.Task(slow_operation(future))
295+
loop.create_task(slow_operation(future))
296296
future.add_done_callback(got_result)
297297
try:
298298
loop.run_forever()
@@ -314,7 +314,33 @@ Task
314314

315315
.. class:: Task(coro, \*, loop=None)
316316

317-
A coroutine object wrapped in a :class:`Future`. Subclass of :class:`Future`.
317+
Schedule the execution of a :ref:`coroutine <coroutine>`: wrap it in a
318+
future. A task is a subclass of :class:`Future`.
319+
320+
A task is responsible to execute a coroutine object in an event loop. If
321+
the wrapped coroutine yields from a future, the task suspends the execution
322+
of the wrapped coroutine and waits for the completition of the future. When
323+
the future is done, the execution of the wrapped coroutine restarts with the
324+
result or the exception of the future.
325+
326+
Event loops use cooperative scheduling: an event loop only runs one task at
327+
the same time. Other tasks may run in parallel if other event loops are
328+
running in different threads. While a task waits for the completion of a
329+
future, the event loop executes a new task.
330+
331+
The cancellation of a task is different than cancelling a future. Calling
332+
:meth:`cancel` will throw a :exc:`~concurrent.futures.CancelledError` to the
333+
wrapped coroutine. :meth:`~Future.cancelled` only returns ``True`` if the
334+
wrapped coroutine did not catch the
335+
:exc:`~concurrent.futures.CancelledError` exception, or raised a
336+
:exc:`~concurrent.futures.CancelledError` exception.
337+
338+
If a pending task is destroyed, the execution of its wrapped :ref:`coroutine
339+
<coroutine>` did not complete. It is probably a bug and a warning is
340+
logged: see :ref:`Pending task destroyed <asyncio-pending-task-destroyed>`.
341+
342+
Don't create directly :class:`Task` instances: use the
343+
:meth:`BaseEventLoop.create_task` method.
318344

319345
.. classmethod:: all_tasks(loop=None)
320346

@@ -396,12 +422,11 @@ Example executing 3 tasks (A, B, C) in parallel::
396422
f *= i
397423
print("Task %s: factorial(%s) = %s" % (name, number, f))
398424

399-
tasks = [
400-
asyncio.Task(factorial("A", 2)),
401-
asyncio.Task(factorial("B", 3)),
402-
asyncio.Task(factorial("C", 4))]
403-
404425
loop = asyncio.get_event_loop()
426+
tasks = [
427+
loop.create_task(factorial("A", 2)),
428+
loop.create_task(factorial("B", 3)),
429+
loop.create_task(factorial("C", 4))]
405430
loop.run_until_complete(asyncio.wait(tasks))
406431
loop.close()
407432

@@ -450,7 +475,8 @@ Task functions
450475

451476
.. function:: async(coro_or_future, \*, loop=None)
452477

453-
Wrap a :ref:`coroutine object <coroutine>` in a future.
478+
Wrap a :ref:`coroutine object <coroutine>` in a future using the
479+
:meth:`BaseEventLoop.create_task` method.
454480

455481
If the argument is a :class:`Future`, it is returned directly.
456482

@@ -566,18 +592,17 @@ Task functions
566592
.. function:: wait_for(fut, timeout, \*, loop=None)
567593

568594
Wait for the single :class:`Future` or :ref:`coroutine object <coroutine>`
569-
to complete, with timeout. If *timeout* is ``None``, block until the future
595+
to complete with timeout. If *timeout* is ``None``, block until the future
570596
completes.
571597

572-
Coroutine will be wrapped in :class:`Task`.
598+
Coroutine objects are wrapped in a future using the
599+
:meth:`BaseEventLoop.create_task` method.
573600

574601
Returns result of the Future or coroutine. When a timeout occurs, it
575602
cancels the task and raises :exc:`asyncio.TimeoutError`. To avoid the task
576603
cancellation, wrap it in :func:`shield`.
577604

578-
This function is a :ref:`coroutine <coroutine>`.
579-
580-
Usage::
605+
This function is a :ref:`coroutine <coroutine>`, usage::
581606

582-
result = yield from asyncio.wait_for(fut, 60.0)
607+
result = yield from asyncio.wait_for(fut, 60.0)
583608

0 commit comments

Comments
 (0)