blob: cb574c308ad1bd3a6a8af6ca188a2724afbd63c9 [file] [log] [blame]
Victor Stinnerdb39a0d2014-01-16 18:58:01 +01001.. currentmodule:: asyncio
2
Victor Stinner0f3e6bc2014-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 Stinner62511fd2014-06-23 00:36:11 +020012.. _asyncio-debug-mode:
13
14Debug mode of asyncio
15---------------------
16
Andrew Svetlov49199072015-09-24 14:32:39 +030017The implementation of :mod:`asyncio` has been written for performance.
18In order to ease the development of asynchronous code, you may wish to
19enable *debug mode*.
Victor Stinnerd71dcbb2014-08-25 17:04:12 +020020
Andrew Svetlov49199072015-09-24 14:32:39 +030021To enable all debug checks for an application:
Victor Stinnerd71dcbb2014-08-25 17:04:12 +020022
Victor Stinner6a1b0042015-02-04 16:14:33 +010023* Enable the asyncio debug mode globally by setting the environment variable
Victor Stinner44862df2017-11-20 07:14:07 -080024 :envvar:`PYTHONASYNCIODEBUG` to ``1``, using ``-X dev`` command line option
25 (see the :option:`-X` option), or by calling
Yury Selivanov7c7605f2018-09-11 09:54:40 -070026 :meth:`loop.set_debug`.
Victor Stinner6a1b0042015-02-04 16:14:33 +010027* Set the log level of the :ref:`asyncio logger <asyncio-logger>` to
28 :py:data:`logging.DEBUG`. For example, call
29 ``logging.basicConfig(level=logging.DEBUG)`` at startup.
30* Configure the :mod:`warnings` module to display :exc:`ResourceWarning`
31 warnings. For example, use the ``-Wdefault`` command line option of Python to
32 display them.
33
34Examples debug checks:
Victor Stinner62511fd2014-06-23 00:36:11 +020035
36* Log :ref:`coroutines defined but never "yielded from"
37 <asyncio-coroutine-not-scheduled>`
Yury Selivanov7c7605f2018-09-11 09:54:40 -070038* :meth:`loop.call_soon` and :meth:`loop.call_at` methods
Victor Stinner62511fd2014-06-23 00:36:11 +020039 raise an exception if they are called from the wrong thread.
40* Log the execution time of the selector
41* Log callbacks taking more than 100 ms to be executed. The
Yury Selivanov7c7605f2018-09-11 09:54:40 -070042 :attr:`loop.slow_callback_duration` attribute is the minimum
Victor Stinner62511fd2014-06-23 00:36:11 +020043 duration in seconds of "slow" callbacks.
Victor Stinner6a1b0042015-02-04 16:14:33 +010044* :exc:`ResourceWarning` warnings are emitted when transports and event loops
45 are :ref:`not closed explicitly <asyncio-close-transports>`.
Victor Stinner62511fd2014-06-23 00:36:11 +020046
Victor Stinner44862df2017-11-20 07:14:07 -080047.. versionchanged:: 3.7
48
49 The new ``-X dev`` command line option can now also be used to enable
50 the debug mode.
51
Victor Stinner62511fd2014-06-23 00:36:11 +020052.. seealso::
53
Yury Selivanov7c7605f2018-09-11 09:54:40 -070054 The :meth:`loop.set_debug` method and the :ref:`asyncio logger
Victor Stinner62511fd2014-06-23 00:36:11 +020055 <asyncio-logger>`.
56
57
Victor Stinner1077dee2015-01-30 00:55:58 +010058Cancellation
59------------
60
61Cancellation of tasks is not common in classic programming. In asynchronous
Mike DePalatis87c3c5d2017-08-03 10:20:42 -040062programming, not only is it something common, but you have to prepare your
Victor Stinner1077dee2015-01-30 00:55:58 +010063code to handle it.
64
65Futures and tasks can be cancelled explicitly with their :meth:`Future.cancel`
66method. The :func:`wait_for` function cancels the waited task when the timeout
67occurs. There are many other cases where a task can be cancelled indirectly.
68
69Don't call :meth:`~Future.set_result` or :meth:`~Future.set_exception` method
70of :class:`Future` if the future is cancelled: it would fail with an exception.
71For example, write::
72
73 if not fut.cancelled():
74 fut.set_result('done')
75
76Don't schedule directly a call to the :meth:`~Future.set_result` or the
77:meth:`~Future.set_exception` method of a future with
Yury Selivanov7c7605f2018-09-11 09:54:40 -070078:meth:`loop.call_soon`: the future can be cancelled before its method
Victor Stinner1077dee2015-01-30 00:55:58 +010079is called.
80
81If you wait for a future, you should check early if the future was cancelled to
82avoid useless operations. Example::
83
Andrew Svetlov88743422017-12-11 17:35:49 +020084 async def slow_operation(fut):
Victor Stinner1077dee2015-01-30 00:55:58 +010085 if fut.cancelled():
86 return
87 # ... slow computation ...
Andrew Svetlov88743422017-12-11 17:35:49 +020088 await fut
Victor Stinner1077dee2015-01-30 00:55:58 +010089 # ...
90
91The :func:`shield` function can also be used to ignore cancellation.
92
93
Victor Stinner606ab032014-02-01 03:18:58 +010094.. _asyncio-multithreading:
95
96Concurrency and multithreading
97------------------------------
98
Yury Selivanov7c7605f2018-09-11 09:54:40 -070099An event loop runs in a thread (typically the main thread) and executes
100all callbacks and tasks in its thread. While a task is running in the
101event loop, no other task is running in the same thread. When a task
102executes an ``await`` expression, the task gets suspended and the
103event loop executes the next task.
Victor Stinner606ab032014-02-01 03:18:58 +0100104
Victor Stinner5cb84ed2014-02-04 18:18:27 +0100105To schedule a callback from a different thread, the
Yury Selivanov7c7605f2018-09-11 09:54:40 -0700106:meth:`loop.call_soon_threadsafe` method should be used. Example::
Victor Stinner5cb84ed2014-02-04 18:18:27 +0100107
Guido van Rossum601953b2015-10-05 16:20:00 -0700108 loop.call_soon_threadsafe(callback, *args)
Victor Stinner606ab032014-02-01 03:18:58 +0100109
Victor Stinner790202d2014-02-07 19:03:05 +0100110Most asyncio objects are not thread safe. You should only worry if you access
111objects outside the event loop. For example, to cancel a future, don't call
112directly its :meth:`Future.cancel` method, but::
113
114 loop.call_soon_threadsafe(fut.cancel)
115
Victor Stinner606ab032014-02-01 03:18:58 +0100116To handle signals and to execute subprocesses, the event loop must be run in
117the main thread.
118
Guido van Rossum601953b2015-10-05 16:20:00 -0700119To schedule a coroutine object from a different thread, the
120:func:`run_coroutine_threadsafe` function should be used. It returns a
121:class:`concurrent.futures.Future` to access the result::
122
123 future = asyncio.run_coroutine_threadsafe(coro_func(), loop)
124 result = future.result(timeout) # Wait for the result with a timeout
125
Yury Selivanov7c7605f2018-09-11 09:54:40 -0700126The :meth:`loop.run_in_executor` method can be used with a thread pool
Victor Stinner606ab032014-02-01 03:18:58 +0100127executor to execute a callback in different thread to not block the thread of
128the event loop.
129
130.. seealso::
131
Zachary Ware5819cfa2015-01-06 00:40:43 -0600132 The :ref:`Synchronization primitives <asyncio-sync>` section describes ways
133 to synchronize tasks.
Victor Stinner606ab032014-02-01 03:18:58 +0100134
Victor Stinner399c59d2015-01-09 01:32:02 +0100135 The :ref:`Subprocess and threads <asyncio-subprocess-threads>` section lists
136 asyncio limitations to run subprocesses from different threads.
137
138
139
Victor Stinner606ab032014-02-01 03:18:58 +0100140
Victor Stinner45b27ed2014-02-01 02:36:43 +0100141.. _asyncio-handle-blocking:
142
Eli Benderskyb73c8332014-02-09 06:07:47 -0800143Handle blocking functions correctly
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100144-----------------------------------
145
146Blocking functions should not be called directly. For example, if a function
147blocks for 1 second, other tasks are delayed by 1 second which can have an
148important impact on reactivity.
149
150For networking and subprocesses, the :mod:`asyncio` module provides high-level
Victor Stinner9592edb2014-02-02 15:03:02 +0100151APIs like :ref:`protocols <asyncio-protocol>`.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100152
153An executor can be used to run a task in a different thread or even in a
154different process, to not block the thread of the event loop. See the
Yury Selivanov7c7605f2018-09-11 09:54:40 -0700155:meth:`loop.run_in_executor` method.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100156
Victor Stinner45b27ed2014-02-01 02:36:43 +0100157.. seealso::
158
159 The :ref:`Delayed calls <asyncio-delayed-calls>` section details how the
160 event loop handles time.
161
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100162
163.. _asyncio-logger:
164
Victor Stinner45b27ed2014-02-01 02:36:43 +0100165Logging
166-------
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100167
Victor Stinner45b27ed2014-02-01 02:36:43 +0100168The :mod:`asyncio` module logs information with the :mod:`logging` module in
169the logger ``'asyncio'``.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100170
Guido van Rossumba29a4f2016-10-13 13:56:40 -0700171The default log level for the :mod:`asyncio` module is :py:data:`logging.INFO`.
172For those not wanting such verbosity from :mod:`asyncio` the log level can
173be changed. For example, to change the level to :py:data:`logging.WARNING`:
174
175.. code-block:: none
176
177 logging.getLogger('asyncio').setLevel(logging.WARNING)
178
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100179
180.. _asyncio-coroutine-not-scheduled:
181
182Detect coroutine objects never scheduled
183----------------------------------------
184
Victor Stinner530ef2f2014-07-08 12:39:10 +0200185When a coroutine function is called and its result is not passed to
Yury Selivanov7c7605f2018-09-11 09:54:40 -0700186:func:`ensure_future` or to the :meth:`loop.create_task` method,
Yury Selivanov04356e12015-06-30 22:13:22 -0400187the execution of the coroutine object will never be scheduled which is
188probably a bug. :ref:`Enable the debug mode of asyncio <asyncio-debug-mode>`
189to :ref:`log a warning <asyncio-logger>` to detect it.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100190
191Example with the bug::
192
193 import asyncio
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100194
Andrew Svetlov88743422017-12-11 17:35:49 +0200195 async def test():
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100196 print("never scheduled")
197
198 test()
199
200Output in debug mode::
201
Victor Stinner530ef2f2014-07-08 12:39:10 +0200202 Coroutine test() at test.py:3 was never yielded from
203 Coroutine object created at (most recent call last):
204 File "test.py", line 7, in <module>
205 test()
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100206
Yury Selivanov04356e12015-06-30 22:13:22 -0400207The fix is to call the :func:`ensure_future` function or the
Yury Selivanov7c7605f2018-09-11 09:54:40 -0700208:meth:`loop.create_task` method with the coroutine object.
Victor Stinner530ef2f2014-07-08 12:39:10 +0200209
210.. seealso::
211
212 :ref:`Pending task destroyed <asyncio-pending-task-destroyed>`.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100213
214
Victor Stinner530ef2f2014-07-08 12:39:10 +0200215Detect exceptions never consumed
216--------------------------------
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100217
Ashley Cambaf8802d82017-11-25 00:39:39 +0100218Python usually calls :func:`sys.excepthook` on unhandled exceptions. If
Victor Stinner530ef2f2014-07-08 12:39:10 +0200219:meth:`Future.set_exception` is called, but the exception is never consumed,
Ashley Cambaf8802d82017-11-25 00:39:39 +0100220:func:`sys.excepthook` is not called. Instead, :ref:`a log is emitted
Victor Stinner530ef2f2014-07-08 12:39:10 +0200221<asyncio-logger>` when the future is deleted by the garbage collector, with the
222traceback where the exception was raised.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100223
224Example of unhandled exception::
225
226 import asyncio
227
228 @asyncio.coroutine
229 def bug():
230 raise Exception("not consumed")
231
232 loop = asyncio.get_event_loop()
Yury Selivanovd7e19bb2015-05-11 16:33:41 -0400233 asyncio.ensure_future(bug())
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100234 loop.run_forever()
Victor Stinnerb8064a82015-02-23 11:41:56 +0100235 loop.close()
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100236
237Output::
238
Victor Stinner530ef2f2014-07-08 12:39:10 +0200239 Task exception was never retrieved
Victor Stinnerab1c8532014-10-12 21:37:16 +0200240 future: <Task finished coro=<coro() done, defined at asyncio/coroutines.py:139> exception=Exception('not consumed',)>
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100241 Traceback (most recent call last):
Victor Stinnerab1c8532014-10-12 21:37:16 +0200242 File "asyncio/tasks.py", line 237, in _step
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100243 result = next(coro)
Victor Stinner530ef2f2014-07-08 12:39:10 +0200244 File "asyncio/coroutines.py", line 141, in coro
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100245 res = func(*args, **kw)
Victor Stinnerab1c8532014-10-12 21:37:16 +0200246 File "test.py", line 5, in bug
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100247 raise Exception("not consumed")
248 Exception: not consumed
249
Victor Stinner530ef2f2014-07-08 12:39:10 +0200250:ref:`Enable the debug mode of asyncio <asyncio-debug-mode>` to get the
Victor Stinnerab1c8532014-10-12 21:37:16 +0200251traceback where the task was created. Output in debug mode::
252
253 Task exception was never retrieved
254 future: <Task finished coro=<bug() done, defined at test.py:3> exception=Exception('not consumed',) created at test.py:8>
255 source_traceback: Object created at (most recent call last):
256 File "test.py", line 8, in <module>
Yury Selivanovd7e19bb2015-05-11 16:33:41 -0400257 asyncio.ensure_future(bug())
Victor Stinnerab1c8532014-10-12 21:37:16 +0200258 Traceback (most recent call last):
259 File "asyncio/tasks.py", line 237, in _step
260 result = next(coro)
261 File "asyncio/coroutines.py", line 79, in __next__
262 return next(self.gen)
263 File "asyncio/coroutines.py", line 141, in coro
264 res = func(*args, **kw)
265 File "test.py", line 5, in bug
266 raise Exception("not consumed")
267 Exception: not consumed
Victor Stinner530ef2f2014-07-08 12:39:10 +0200268
Zachary Ware5819cfa2015-01-06 00:40:43 -0600269There are different options to fix this issue. The first option is to chain the
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100270coroutine in another coroutine and use classic try/except::
271
Andrew Svetlov88743422017-12-11 17:35:49 +0200272 async def handle_exception():
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100273 try:
Andrew Svetlov88743422017-12-11 17:35:49 +0200274 await bug()
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100275 except Exception:
276 print("exception consumed")
277
278 loop = asyncio.get_event_loop()
Yury Selivanovd7e19bb2015-05-11 16:33:41 -0400279 asyncio.ensure_future(handle_exception())
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100280 loop.run_forever()
Victor Stinnerb8064a82015-02-23 11:41:56 +0100281 loop.close()
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100282
Yury Selivanov7c7605f2018-09-11 09:54:40 -0700283Another option is to use the :meth:`loop.run_until_complete`
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100284function::
285
Yury Selivanovd7e19bb2015-05-11 16:33:41 -0400286 task = asyncio.ensure_future(bug())
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100287 try:
288 loop.run_until_complete(task)
289 except Exception:
290 print("exception consumed")
291
Zachary Ware5819cfa2015-01-06 00:40:43 -0600292.. seealso::
293
294 The :meth:`Future.exception` method.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100295
296
Zachary Ware5819cfa2015-01-06 00:40:43 -0600297Chain coroutines correctly
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100298--------------------------
299
300When a coroutine function calls other coroutine functions and tasks, they
Andrew Svetlov88743422017-12-11 17:35:49 +0200301should be chained explicitly with ``await``. Otherwise, the execution is
Eli Bendersky679688e2014-01-20 08:13:31 -0800302not guaranteed to be sequential.
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100303
Eli Bendersky679688e2014-01-20 08:13:31 -0800304Example with different bugs using :func:`asyncio.sleep` to simulate slow
305operations::
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100306
307 import asyncio
308
Andrew Svetlov88743422017-12-11 17:35:49 +0200309 async def create():
310 await asyncio.sleep(3.0)
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100311 print("(1) create file")
312
Andrew Svetlov88743422017-12-11 17:35:49 +0200313 async def write():
314 await asyncio.sleep(1.0)
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100315 print("(2) write into file")
316
Andrew Svetlov88743422017-12-11 17:35:49 +0200317 async def close():
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100318 print("(3) close file")
319
Andrew Svetlov88743422017-12-11 17:35:49 +0200320 async def test():
Yury Selivanovd7e19bb2015-05-11 16:33:41 -0400321 asyncio.ensure_future(create())
322 asyncio.ensure_future(write())
323 asyncio.ensure_future(close())
Andrew Svetlov88743422017-12-11 17:35:49 +0200324 await asyncio.sleep(2.0)
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100325 loop.stop()
326
327 loop = asyncio.get_event_loop()
Yury Selivanovd7e19bb2015-05-11 16:33:41 -0400328 asyncio.ensure_future(test())
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100329 loop.run_forever()
330 print("Pending tasks at exit: %s" % asyncio.Task.all_tasks(loop))
Victor Stinnerf40c6632014-01-28 23:32:40 +0100331 loop.close()
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100332
Martin Panter1050d2d2016-07-26 11:18:21 +0200333Expected output:
334
335.. code-block:: none
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100336
337 (1) create file
338 (2) write into file
339 (3) close file
340 Pending tasks at exit: set()
341
Martin Panter1050d2d2016-07-26 11:18:21 +0200342Actual output:
343
344.. code-block:: none
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100345
346 (3) close file
347 (2) write into file
Victor Stinner530ef2f2014-07-08 12:39:10 +0200348 Pending tasks at exit: {<Task pending create() at test.py:7 wait_for=<Future pending cb=[Task._wakeup()]>>}
349 Task was destroyed but it is pending!
350 task: <Task pending create() done at test.py:5 wait_for=<Future pending cb=[Task._wakeup()]>>
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100351
352The loop stopped before the ``create()`` finished, ``close()`` has been called
353before ``write()``, whereas coroutine functions were called in this order:
354``create()``, ``write()``, ``close()``.
355
Andrew Svetlov88743422017-12-11 17:35:49 +0200356To fix the example, tasks must be marked with ``await``::
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100357
Andrew Svetlov88743422017-12-11 17:35:49 +0200358 async def test():
359 await asyncio.ensure_future(create())
360 await asyncio.ensure_future(write())
361 await asyncio.ensure_future(close())
362 await asyncio.sleep(2.0)
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100363 loop.stop()
364
Yury Selivanovd7e19bb2015-05-11 16:33:41 -0400365Or without ``asyncio.ensure_future()``::
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100366
Andrew Svetlov88743422017-12-11 17:35:49 +0200367 async def test():
368 await create()
369 await write()
370 await close()
371 await asyncio.sleep(2.0)
Victor Stinnerdb39a0d2014-01-16 18:58:01 +0100372 loop.stop()
373
Victor Stinner530ef2f2014-07-08 12:39:10 +0200374
375.. _asyncio-pending-task-destroyed:
376
377Pending task destroyed
378----------------------
379
380If a pending task is destroyed, the execution of its wrapped :ref:`coroutine
381<coroutine>` did not complete. It is probably a bug and so a warning is logged.
382
Martin Panter1050d2d2016-07-26 11:18:21 +0200383Example of log:
384
385.. code-block:: none
Victor Stinner530ef2f2014-07-08 12:39:10 +0200386
387 Task was destroyed but it is pending!
Victor Stinnerab1c8532014-10-12 21:37:16 +0200388 task: <Task pending coro=<kill_me() done, defined at test.py:5> wait_for=<Future pending cb=[Task._wakeup()]>>
Victor Stinner530ef2f2014-07-08 12:39:10 +0200389
390:ref:`Enable the debug mode of asyncio <asyncio-debug-mode>` to get the
Martin Panter1050d2d2016-07-26 11:18:21 +0200391traceback where the task was created. Example of log in debug mode:
392
393.. code-block:: none
Victor Stinnerab1c8532014-10-12 21:37:16 +0200394
395 Task was destroyed but it is pending!
396 source_traceback: Object created at (most recent call last):
397 File "test.py", line 15, in <module>
Yury Selivanovd7e19bb2015-05-11 16:33:41 -0400398 task = asyncio.ensure_future(coro, loop=loop)
Victor Stinnerab1c8532014-10-12 21:37:16 +0200399 task: <Task pending coro=<kill_me() done, defined at test.py:5> wait_for=<Future pending cb=[Task._wakeup()] created at test.py:7> created at test.py:15>
400
Victor Stinner530ef2f2014-07-08 12:39:10 +0200401
402.. seealso::
403
404 :ref:`Detect coroutine objects never scheduled <asyncio-coroutine-not-scheduled>`.
405
Victor Stinner6a1b0042015-02-04 16:14:33 +0100406.. _asyncio-close-transports:
Victor Stinner188f2c02015-01-30 01:35:14 +0100407
Victor Stinner6a1b0042015-02-04 16:14:33 +0100408Close transports and event loops
409--------------------------------
Victor Stinner188f2c02015-01-30 01:35:14 +0100410
411When a transport is no more needed, call its ``close()`` method to release
Victor Stinner6a1b0042015-02-04 16:14:33 +0100412resources. Event loops must also be closed explicitly.
Victor Stinner188f2c02015-01-30 01:35:14 +0100413
Victor Stinner6a1b0042015-02-04 16:14:33 +0100414If a transport or an event loop is not closed explicitly, a
415:exc:`ResourceWarning` warning will be emitted in its destructor. By default,
416:exc:`ResourceWarning` warnings are ignored. The :ref:`Debug mode of asyncio
417<asyncio-debug-mode>` section explains how to display them.