blob: 9d6f054a7ce393c85ab5f4815deddb5669b21db4 [file] [log] [blame]
Victor Stinnerdb39a0d2014-01-16 18:58:01 +01001.. currentmodule:: asyncio
2
Victor Stinner7ef60cd2014-02-19 23:15:02 +01003.. _asyncio-dev:
4
Victor Stinnerdb39a0d2014-01-16 18:58:01 +01005Develop with asyncio
6====================
7
8Asynchronous programming is different than classical "sequential" programming.
Eli Bendersky679688e2014-01-20 08:13:31 -08009This page lists common traps and explains how to avoid them.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010010
11
Victor Stinner606ab032014-02-01 03:18:58 +010012.. _asyncio-multithreading:
13
14Concurrency and multithreading
15------------------------------
16
17An event loop runs in a thread and executes all callbacks and tasks in the same
Victor Stinner0aba4dc2014-02-18 09:22:00 +010018thread. While a task is running in the event loop, no other task is running in
Victor Stinner5cb84ed2014-02-04 18:18:27 +010019the same thread. But when the task uses ``yield from``, the task is suspended
20and the event loop executes the next task.
Victor Stinner606ab032014-02-01 03:18:58 +010021
Victor Stinner5cb84ed2014-02-04 18:18:27 +010022To schedule a callback from a different thread, the
23:meth:`BaseEventLoop.call_soon_threadsafe` method should be used. Example to
Guido van Rossum3c9bb692014-02-04 13:49:34 -080024schedule a coroutine from a different thread::
Victor Stinner5cb84ed2014-02-04 18:18:27 +010025
26 loop.call_soon_threadsafe(asyncio.async, coro_func())
Victor Stinner606ab032014-02-01 03:18:58 +010027
Victor Stinner790202d2014-02-07 19:03:05 +010028Most asyncio objects are not thread safe. You should only worry if you access
29objects outside the event loop. For example, to cancel a future, don't call
30directly its :meth:`Future.cancel` method, but::
31
32 loop.call_soon_threadsafe(fut.cancel)
33
Victor Stinner606ab032014-02-01 03:18:58 +010034To handle signals and to execute subprocesses, the event loop must be run in
35the main thread.
36
37The :meth:`BaseEventLoop.run_in_executor` method can be used with a thread pool
38executor to execute a callback in different thread to not block the thread of
39the event loop.
40
41.. seealso::
42
43 See the :ref:`Synchronization primitives <asyncio-sync>` section to
44 synchronize tasks.
45
46
Victor Stinner45b27ed2014-02-01 02:36:43 +010047.. _asyncio-handle-blocking:
48
Eli Benderskyb73c8332014-02-09 06:07:47 -080049Handle blocking functions correctly
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010050-----------------------------------
51
52Blocking functions should not be called directly. For example, if a function
53blocks for 1 second, other tasks are delayed by 1 second which can have an
54important impact on reactivity.
55
56For networking and subprocesses, the :mod:`asyncio` module provides high-level
Victor Stinner9592edb2014-02-02 15:03:02 +010057APIs like :ref:`protocols <asyncio-protocol>`.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010058
59An executor can be used to run a task in a different thread or even in a
60different process, to not block the thread of the event loop. See the
Victor Stinner606ab032014-02-01 03:18:58 +010061:meth:`BaseEventLoop.run_in_executor` method.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010062
Victor Stinner45b27ed2014-02-01 02:36:43 +010063.. seealso::
64
65 The :ref:`Delayed calls <asyncio-delayed-calls>` section details how the
66 event loop handles time.
67
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010068
69.. _asyncio-logger:
70
Victor Stinner45b27ed2014-02-01 02:36:43 +010071Logging
72-------
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010073
Victor Stinner45b27ed2014-02-01 02:36:43 +010074The :mod:`asyncio` module logs information with the :mod:`logging` module in
75the logger ``'asyncio'``.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010076
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010077
78.. _asyncio-coroutine-not-scheduled:
79
80Detect coroutine objects never scheduled
81----------------------------------------
82
83When a coroutine function is called but not passed to :func:`async` or to the
84:class:`Task` constructor, it is not scheduled and it is probably a bug.
85
Victor Stinner7ef60cd2014-02-19 23:15:02 +010086To detect such bug, set the environment variable :envvar:`PYTHONASYNCIODEBUG`
87to ``1``. When the coroutine object is destroyed by the garbage collector, a
88log will be emitted with the traceback where the coroutine function was called.
89See the :ref:`asyncio logger <asyncio-logger>`.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010090
91The debug flag changes the behaviour of the :func:`coroutine` decorator. The
Victor Stinner97311832014-01-17 10:31:02 +010092debug flag value is only used when then coroutine function is defined, not when
93it is called. Coroutine functions defined before the debug flag is set to
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010094``True`` will not be tracked. For example, it is not possible to debug
95coroutines defined in the :mod:`asyncio` module, because the module must be
96imported before the flag value can be changed.
97
98Example with the bug::
99
100 import asyncio
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100101
102 @asyncio.coroutine
103 def test():
104 print("never scheduled")
105
106 test()
107
108Output in debug mode::
109
110 Coroutine 'test' defined at test.py:4 was never yielded from
111
112The fix is to call the :func:`async` function or create a :class:`Task` object
113with this coroutine object.
114
115
116Detect exceptions not consumed
117------------------------------
118
119Python usually calls :func:`sys.displayhook` on unhandled exceptions. If
120:meth:`Future.set_exception` is called, but the exception is not consumed,
121:func:`sys.displayhook` is not called. Instead, a log is emitted when the
122future is deleted by the garbage collector, with the traceback where the
123exception was raised. See the :ref:`asyncio logger <asyncio-logger>`.
124
125Example of unhandled exception::
126
127 import asyncio
128
129 @asyncio.coroutine
130 def bug():
131 raise Exception("not consumed")
132
133 loop = asyncio.get_event_loop()
134 asyncio.async(bug())
135 loop.run_forever()
136
137Output::
138
139 Future/Task exception was never retrieved:
140 Traceback (most recent call last):
141 File "/usr/lib/python3.4/asyncio/tasks.py", line 279, in _step
142 result = next(coro)
143 File "/usr/lib/python3.4/asyncio/tasks.py", line 80, in coro
144 res = func(*args, **kw)
145 File "test.py", line 5, in bug
146 raise Exception("not consumed")
147 Exception: not consumed
148
149There are different options to fix this issue. The first option is to chain to
150coroutine in another coroutine and use classic try/except::
151
152 @asyncio.coroutine
153 def handle_exception():
154 try:
155 yield from bug()
156 except Exception:
157 print("exception consumed")
158
159 loop = asyncio.get_event_loop()
160 asyncio.async(handle_exception())
161 loop.run_forever()
162
163Another option is to use the :meth:`BaseEventLoop.run_until_complete`
164function::
165
166 task = asyncio.async(bug())
167 try:
168 loop.run_until_complete(task)
169 except Exception:
170 print("exception consumed")
171
172See also the :meth:`Future.exception` method.
173
174
Eli Bendersky679688e2014-01-20 08:13:31 -0800175Chain coroutines correctly
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100176--------------------------
177
178When a coroutine function calls other coroutine functions and tasks, they
Eli Bendersky679688e2014-01-20 08:13:31 -0800179should be chained explicitly with ``yield from``. Otherwise, the execution is
180not guaranteed to be sequential.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100181
Eli Bendersky679688e2014-01-20 08:13:31 -0800182Example with different bugs using :func:`asyncio.sleep` to simulate slow
183operations::
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100184
185 import asyncio
186
187 @asyncio.coroutine
188 def create():
189 yield from asyncio.sleep(3.0)
190 print("(1) create file")
191
192 @asyncio.coroutine
193 def write():
194 yield from asyncio.sleep(1.0)
195 print("(2) write into file")
196
197 @asyncio.coroutine
198 def close():
199 print("(3) close file")
200
201 @asyncio.coroutine
202 def test():
203 asyncio.async(create())
204 asyncio.async(write())
205 asyncio.async(close())
206 yield from asyncio.sleep(2.0)
207 loop.stop()
208
209 loop = asyncio.get_event_loop()
210 asyncio.async(test())
211 loop.run_forever()
212 print("Pending tasks at exit: %s" % asyncio.Task.all_tasks(loop))
Victor Stinnerf40c6632014-01-28 23:32:40 +0100213 loop.close()
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100214
215Expected output::
216
217 (1) create file
218 (2) write into file
219 (3) close file
220 Pending tasks at exit: set()
221
222Actual output::
223
224 (3) close file
225 (2) write into file
226 Pending tasks at exit: {Task(<create>)<PENDING>}
227
228The loop stopped before the ``create()`` finished, ``close()`` has been called
229before ``write()``, whereas coroutine functions were called in this order:
230``create()``, ``write()``, ``close()``.
231
232To fix the example, tasks must be marked with ``yield from``::
233
234 @asyncio.coroutine
235 def test():
236 yield from asyncio.async(create())
237 yield from asyncio.async(write())
238 yield from asyncio.async(close())
239 yield from asyncio.sleep(2.0)
240 loop.stop()
241
242Or without ``asyncio.async()``::
243
244 @asyncio.coroutine
245 def test():
246 yield from create()
247 yield from write()
248 yield from close()
249 yield from asyncio.sleep(2.0)
250 loop.stop()
251