blob: 90bae8440ee74b606bee1318eae86a12348b5761 [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 Stinner0aba4dc2014-02-18 09:22:00 +010016thread. While a task is running in the event loop, no other task is running in
Victor Stinner5cb84ed2014-02-04 18:18:27 +010017the 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
Victor Stinner790202d2014-02-07 19:03:05 +010026Most asyncio objects are not thread safe. You should only worry if you access
27objects outside the event loop. For example, to cancel a future, don't call
28directly its :meth:`Future.cancel` method, but::
29
30 loop.call_soon_threadsafe(fut.cancel)
31
Victor Stinner606ab032014-02-01 03:18:58 +010032To handle signals and to execute subprocesses, the event loop must be run in
33the main thread.
34
35The :meth:`BaseEventLoop.run_in_executor` method can be used with a thread pool
36executor to execute a callback in different thread to not block the thread of
37the event loop.
38
39.. seealso::
40
41 See the :ref:`Synchronization primitives <asyncio-sync>` section to
42 synchronize tasks.
43
44
Victor Stinner45b27ed2014-02-01 02:36:43 +010045.. _asyncio-handle-blocking:
46
Eli Benderskyb73c8332014-02-09 06:07:47 -080047Handle blocking functions correctly
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010048-----------------------------------
49
50Blocking functions should not be called directly. For example, if a function
51blocks for 1 second, other tasks are delayed by 1 second which can have an
52important impact on reactivity.
53
54For networking and subprocesses, the :mod:`asyncio` module provides high-level
Victor Stinner9592edb2014-02-02 15:03:02 +010055APIs like :ref:`protocols <asyncio-protocol>`.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010056
57An executor can be used to run a task in a different thread or even in a
58different process, to not block the thread of the event loop. See the
Victor Stinner606ab032014-02-01 03:18:58 +010059:meth:`BaseEventLoop.run_in_executor` method.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010060
Victor Stinner45b27ed2014-02-01 02:36:43 +010061.. seealso::
62
63 The :ref:`Delayed calls <asyncio-delayed-calls>` section details how the
64 event loop handles time.
65
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010066
67.. _asyncio-logger:
68
Victor Stinner45b27ed2014-02-01 02:36:43 +010069Logging
70-------
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010071
Victor Stinner45b27ed2014-02-01 02:36:43 +010072The :mod:`asyncio` module logs information with the :mod:`logging` module in
73the logger ``'asyncio'``.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010074
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010075
76.. _asyncio-coroutine-not-scheduled:
77
78Detect coroutine objects never scheduled
79----------------------------------------
80
81When a coroutine function is called but not passed to :func:`async` or to the
82:class:`Task` constructor, it is not scheduled and it is probably a bug.
83
84To detect such bug, set :data:`asyncio.tasks._DEBUG` to ``True``. When the
85coroutine object is destroyed by the garbage collector, a log will be emitted
86with the traceback where the coroutine function was called. See the
87:ref:`asyncio logger <asyncio-logger>`.
88
89The debug flag changes the behaviour of the :func:`coroutine` decorator. The
Victor Stinner97311832014-01-17 10:31:02 +010090debug flag value is only used when then coroutine function is defined, not when
91it is called. Coroutine functions defined before the debug flag is set to
Victor Stinnerdb39a0d2014-01-16 18:58:01 +010092``True`` will not be tracked. For example, it is not possible to debug
93coroutines defined in the :mod:`asyncio` module, because the module must be
94imported before the flag value can be changed.
95
96Example with the bug::
97
98 import asyncio
99 asyncio.tasks._DEBUG = True
100
101 @asyncio.coroutine
102 def test():
103 print("never scheduled")
104
105 test()
106
107Output in debug mode::
108
109 Coroutine 'test' defined at test.py:4 was never yielded from
110
111The fix is to call the :func:`async` function or create a :class:`Task` object
112with this coroutine object.
113
114
115Detect exceptions not consumed
116------------------------------
117
118Python usually calls :func:`sys.displayhook` on unhandled exceptions. If
119:meth:`Future.set_exception` is called, but the exception is not consumed,
120:func:`sys.displayhook` is not called. Instead, a log is emitted when the
121future is deleted by the garbage collector, with the traceback where the
122exception was raised. See the :ref:`asyncio logger <asyncio-logger>`.
123
124Example of unhandled exception::
125
126 import asyncio
127
128 @asyncio.coroutine
129 def bug():
130 raise Exception("not consumed")
131
132 loop = asyncio.get_event_loop()
133 asyncio.async(bug())
134 loop.run_forever()
135
136Output::
137
138 Future/Task exception was never retrieved:
139 Traceback (most recent call last):
140 File "/usr/lib/python3.4/asyncio/tasks.py", line 279, in _step
141 result = next(coro)
142 File "/usr/lib/python3.4/asyncio/tasks.py", line 80, in coro
143 res = func(*args, **kw)
144 File "test.py", line 5, in bug
145 raise Exception("not consumed")
146 Exception: not consumed
147
148There are different options to fix this issue. The first option is to chain to
149coroutine in another coroutine and use classic try/except::
150
151 @asyncio.coroutine
152 def handle_exception():
153 try:
154 yield from bug()
155 except Exception:
156 print("exception consumed")
157
158 loop = asyncio.get_event_loop()
159 asyncio.async(handle_exception())
160 loop.run_forever()
161
162Another option is to use the :meth:`BaseEventLoop.run_until_complete`
163function::
164
165 task = asyncio.async(bug())
166 try:
167 loop.run_until_complete(task)
168 except Exception:
169 print("exception consumed")
170
171See also the :meth:`Future.exception` method.
172
173
Eli Bendersky679688e2014-01-20 08:13:31 -0800174Chain coroutines correctly
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100175--------------------------
176
177When a coroutine function calls other coroutine functions and tasks, they
Eli Bendersky679688e2014-01-20 08:13:31 -0800178should be chained explicitly with ``yield from``. Otherwise, the execution is
179not guaranteed to be sequential.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100180
Eli Bendersky679688e2014-01-20 08:13:31 -0800181Example with different bugs using :func:`asyncio.sleep` to simulate slow
182operations::
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100183
184 import asyncio
185
186 @asyncio.coroutine
187 def create():
188 yield from asyncio.sleep(3.0)
189 print("(1) create file")
190
191 @asyncio.coroutine
192 def write():
193 yield from asyncio.sleep(1.0)
194 print("(2) write into file")
195
196 @asyncio.coroutine
197 def close():
198 print("(3) close file")
199
200 @asyncio.coroutine
201 def test():
202 asyncio.async(create())
203 asyncio.async(write())
204 asyncio.async(close())
205 yield from asyncio.sleep(2.0)
206 loop.stop()
207
208 loop = asyncio.get_event_loop()
209 asyncio.async(test())
210 loop.run_forever()
211 print("Pending tasks at exit: %s" % asyncio.Task.all_tasks(loop))
Victor Stinnerf40c6632014-01-28 23:32:40 +0100212 loop.close()
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100213
214Expected output::
215
216 (1) create file
217 (2) write into file
218 (3) close file
219 Pending tasks at exit: set()
220
221Actual output::
222
223 (3) close file
224 (2) write into file
225 Pending tasks at exit: {Task(<create>)<PENDING>}
226
227The loop stopped before the ``create()`` finished, ``close()`` has been called
228before ``write()``, whereas coroutine functions were called in this order:
229``create()``, ``write()``, ``close()``.
230
231To fix the example, tasks must be marked with ``yield from``::
232
233 @asyncio.coroutine
234 def test():
235 yield from asyncio.async(create())
236 yield from asyncio.async(write())
237 yield from asyncio.async(close())
238 yield from asyncio.sleep(2.0)
239 loop.stop()
240
241Or without ``asyncio.async()``::
242
243 @asyncio.coroutine
244 def test():
245 yield from create()
246 yield from write()
247 yield from close()
248 yield from asyncio.sleep(2.0)
249 loop.stop()
250