blob: 686e49605315ac59784859115cfe74a86bb4811b [file] [log] [blame]
Victor Stinnerdb39a0d2014-01-16 18:58:01 +01001.. currentmodule:: asyncio
2
3Develop with asyncio
4====================
5
6Asynchronous programming is different than classical "sequential" programming.
Eli Bendersky679688e2014-01-20 08:13:31 -08007This page lists common traps and explains how to avoid them.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +01008
9
Victor Stinner606ab032014-02-01 03:18:58 +010010.. _asyncio-multithreading:
11
12Concurrency and multithreading
13------------------------------
14
15An event loop runs in a thread and executes all callbacks and tasks in the same
Victor Stinner5cb84ed2014-02-04 18:18:27 +010016thread. While a task in running in the event loop, no other task is running in
17the same thread. But when the task uses ``yield from``, the task is suspended
18and the event loop executes the next task.
Victor Stinner606ab032014-02-01 03:18:58 +010019
Victor Stinner5cb84ed2014-02-04 18:18:27 +010020To schedule a callback from a different thread, the
21:meth:`BaseEventLoop.call_soon_threadsafe` method should be used. Example to
Guido van Rossum3c9bb692014-02-04 13:49:34 -080022schedule a coroutine from a different thread::
Victor Stinner5cb84ed2014-02-04 18:18:27 +010023
24 loop.call_soon_threadsafe(asyncio.async, coro_func())
Victor Stinner606ab032014-02-01 03:18:58 +010025
26To handle signals and to execute subprocesses, the event loop must be run in
27the main thread.
28
29The :meth:`BaseEventLoop.run_in_executor` method can be used with a thread pool
30executor to execute a callback in different thread to not block the thread of
31the event loop.
32
33.. seealso::
34
35 See the :ref:`Synchronization primitives <asyncio-sync>` section to
36 synchronize tasks.
37
38
Victor Stinner45b27ed2014-02-01 02:36:43 +010039.. _asyncio-handle-blocking:
40
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010041Handle correctly blocking functions
42-----------------------------------
43
44Blocking functions should not be called directly. For example, if a function
45blocks for 1 second, other tasks are delayed by 1 second which can have an
46important impact on reactivity.
47
48For networking and subprocesses, the :mod:`asyncio` module provides high-level
Victor Stinner9592edb2014-02-02 15:03:02 +010049APIs like :ref:`protocols <asyncio-protocol>`.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010050
51An executor can be used to run a task in a different thread or even in a
52different process, to not block the thread of the event loop. See the
Victor Stinner606ab032014-02-01 03:18:58 +010053:meth:`BaseEventLoop.run_in_executor` method.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010054
Victor Stinner45b27ed2014-02-01 02:36:43 +010055.. seealso::
56
57 The :ref:`Delayed calls <asyncio-delayed-calls>` section details how the
58 event loop handles time.
59
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010060
61.. _asyncio-logger:
62
Victor Stinner45b27ed2014-02-01 02:36:43 +010063Logging
64-------
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010065
Victor Stinner45b27ed2014-02-01 02:36:43 +010066The :mod:`asyncio` module logs information with the :mod:`logging` module in
67the logger ``'asyncio'``.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010068
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010069
70.. _asyncio-coroutine-not-scheduled:
71
72Detect coroutine objects never scheduled
73----------------------------------------
74
75When a coroutine function is called but not passed to :func:`async` or to the
76:class:`Task` constructor, it is not scheduled and it is probably a bug.
77
78To detect such bug, set :data:`asyncio.tasks._DEBUG` to ``True``. When the
79coroutine object is destroyed by the garbage collector, a log will be emitted
80with the traceback where the coroutine function was called. See the
81:ref:`asyncio logger <asyncio-logger>`.
82
83The debug flag changes the behaviour of the :func:`coroutine` decorator. The
Victor Stinner97311832014-01-17 10:31:02 +010084debug flag value is only used when then coroutine function is defined, not when
85it is called. Coroutine functions defined before the debug flag is set to
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010086``True`` will not be tracked. For example, it is not possible to debug
87coroutines defined in the :mod:`asyncio` module, because the module must be
88imported before the flag value can be changed.
89
90Example with the bug::
91
92 import asyncio
93 asyncio.tasks._DEBUG = True
94
95 @asyncio.coroutine
96 def test():
97 print("never scheduled")
98
99 test()
100
101Output in debug mode::
102
103 Coroutine 'test' defined at test.py:4 was never yielded from
104
105The fix is to call the :func:`async` function or create a :class:`Task` object
106with this coroutine object.
107
108
109Detect exceptions not consumed
110------------------------------
111
112Python usually calls :func:`sys.displayhook` on unhandled exceptions. If
113:meth:`Future.set_exception` is called, but the exception is not consumed,
114:func:`sys.displayhook` is not called. Instead, a log is emitted when the
115future is deleted by the garbage collector, with the traceback where the
116exception was raised. See the :ref:`asyncio logger <asyncio-logger>`.
117
118Example of unhandled exception::
119
120 import asyncio
121
122 @asyncio.coroutine
123 def bug():
124 raise Exception("not consumed")
125
126 loop = asyncio.get_event_loop()
127 asyncio.async(bug())
128 loop.run_forever()
129
130Output::
131
132 Future/Task exception was never retrieved:
133 Traceback (most recent call last):
134 File "/usr/lib/python3.4/asyncio/tasks.py", line 279, in _step
135 result = next(coro)
136 File "/usr/lib/python3.4/asyncio/tasks.py", line 80, in coro
137 res = func(*args, **kw)
138 File "test.py", line 5, in bug
139 raise Exception("not consumed")
140 Exception: not consumed
141
142There are different options to fix this issue. The first option is to chain to
143coroutine in another coroutine and use classic try/except::
144
145 @asyncio.coroutine
146 def handle_exception():
147 try:
148 yield from bug()
149 except Exception:
150 print("exception consumed")
151
152 loop = asyncio.get_event_loop()
153 asyncio.async(handle_exception())
154 loop.run_forever()
155
156Another option is to use the :meth:`BaseEventLoop.run_until_complete`
157function::
158
159 task = asyncio.async(bug())
160 try:
161 loop.run_until_complete(task)
162 except Exception:
163 print("exception consumed")
164
165See also the :meth:`Future.exception` method.
166
167
Eli Bendersky679688e2014-01-20 08:13:31 -0800168Chain coroutines correctly
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100169--------------------------
170
171When a coroutine function calls other coroutine functions and tasks, they
Eli Bendersky679688e2014-01-20 08:13:31 -0800172should be chained explicitly with ``yield from``. Otherwise, the execution is
173not guaranteed to be sequential.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100174
Eli Bendersky679688e2014-01-20 08:13:31 -0800175Example with different bugs using :func:`asyncio.sleep` to simulate slow
176operations::
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100177
178 import asyncio
179
180 @asyncio.coroutine
181 def create():
182 yield from asyncio.sleep(3.0)
183 print("(1) create file")
184
185 @asyncio.coroutine
186 def write():
187 yield from asyncio.sleep(1.0)
188 print("(2) write into file")
189
190 @asyncio.coroutine
191 def close():
192 print("(3) close file")
193
194 @asyncio.coroutine
195 def test():
196 asyncio.async(create())
197 asyncio.async(write())
198 asyncio.async(close())
199 yield from asyncio.sleep(2.0)
200 loop.stop()
201
202 loop = asyncio.get_event_loop()
203 asyncio.async(test())
204 loop.run_forever()
205 print("Pending tasks at exit: %s" % asyncio.Task.all_tasks(loop))
Victor Stinnerf40c6632014-01-28 23:32:40 +0100206 loop.close()
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100207
208Expected output::
209
210 (1) create file
211 (2) write into file
212 (3) close file
213 Pending tasks at exit: set()
214
215Actual output::
216
217 (3) close file
218 (2) write into file
219 Pending tasks at exit: {Task(<create>)<PENDING>}
220
221The loop stopped before the ``create()`` finished, ``close()`` has been called
222before ``write()``, whereas coroutine functions were called in this order:
223``create()``, ``write()``, ``close()``.
224
225To fix the example, tasks must be marked with ``yield from``::
226
227 @asyncio.coroutine
228 def test():
229 yield from asyncio.async(create())
230 yield from asyncio.async(write())
231 yield from asyncio.async(close())
232 yield from asyncio.sleep(2.0)
233 loop.stop()
234
235Or without ``asyncio.async()``::
236
237 @asyncio.coroutine
238 def test():
239 yield from create()
240 yield from write()
241 yield from close()
242 yield from asyncio.sleep(2.0)
243 loop.stop()
244