17db96d56Sopenharmony_ci.. currentmodule:: asyncio
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ci.. _asyncio-dev:
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ci=======================
67db96d56Sopenharmony_ciDeveloping with asyncio
77db96d56Sopenharmony_ci=======================
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ciAsynchronous programming is different from classic "sequential"
107db96d56Sopenharmony_ciprogramming.
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ciThis page lists common mistakes and traps and explains how
137db96d56Sopenharmony_cito avoid them.
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci.. _asyncio-debug-mode:
177db96d56Sopenharmony_ci
187db96d56Sopenharmony_ciDebug Mode
197db96d56Sopenharmony_ci==========
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ciBy default asyncio runs in production mode.  In order to ease
227db96d56Sopenharmony_cithe development asyncio has a *debug mode*.
237db96d56Sopenharmony_ci
247db96d56Sopenharmony_ciThere are several ways to enable asyncio debug mode:
257db96d56Sopenharmony_ci
267db96d56Sopenharmony_ci* Setting the :envvar:`PYTHONASYNCIODEBUG` environment variable to ``1``.
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_ci* Using the :ref:`Python Development Mode <devmode>`.
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ci* Passing ``debug=True`` to :func:`asyncio.run`.
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci* Calling :meth:`loop.set_debug`.
337db96d56Sopenharmony_ci
347db96d56Sopenharmony_ciIn addition to enabling the debug mode, consider also:
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_ci* setting the log level of the :ref:`asyncio logger <asyncio-logger>` to
377db96d56Sopenharmony_ci  :py:data:`logging.DEBUG`, for example the following snippet of code
387db96d56Sopenharmony_ci  can be run at startup of the application::
397db96d56Sopenharmony_ci
407db96d56Sopenharmony_ci    logging.basicConfig(level=logging.DEBUG)
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_ci* configuring the :mod:`warnings` module to display
437db96d56Sopenharmony_ci  :exc:`ResourceWarning` warnings.  One way of doing that is by
447db96d56Sopenharmony_ci  using the :option:`-W` ``default`` command line option.
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ciWhen the debug mode is enabled:
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_ci* asyncio checks for :ref:`coroutines that were not awaited
507db96d56Sopenharmony_ci  <asyncio-coroutine-not-scheduled>` and logs them; this mitigates
517db96d56Sopenharmony_ci  the "forgotten await" pitfall.
527db96d56Sopenharmony_ci
537db96d56Sopenharmony_ci* Many non-threadsafe asyncio APIs (such as :meth:`loop.call_soon` and
547db96d56Sopenharmony_ci  :meth:`loop.call_at` methods) raise an exception if they are called
557db96d56Sopenharmony_ci  from a wrong thread.
567db96d56Sopenharmony_ci
577db96d56Sopenharmony_ci* The execution time of the I/O selector is logged if it takes too long to
587db96d56Sopenharmony_ci  perform an I/O operation.
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci* Callbacks taking longer than 100 milliseconds are logged.  The
617db96d56Sopenharmony_ci  :attr:`loop.slow_callback_duration` attribute can be used to set the
627db96d56Sopenharmony_ci  minimum execution duration in seconds that is considered "slow".
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_ci.. _asyncio-multithreading:
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ciConcurrency and Multithreading
687db96d56Sopenharmony_ci==============================
697db96d56Sopenharmony_ci
707db96d56Sopenharmony_ciAn event loop runs in a thread (typically the main thread) and executes
717db96d56Sopenharmony_ciall callbacks and Tasks in its thread.  While a Task is running in the
727db96d56Sopenharmony_cievent loop, no other Tasks can run in the same thread.  When a Task
737db96d56Sopenharmony_ciexecutes an ``await`` expression, the running Task gets suspended, and
747db96d56Sopenharmony_cithe event loop executes the next Task.
757db96d56Sopenharmony_ci
767db96d56Sopenharmony_ciTo schedule a :term:`callback` from another OS thread, the
777db96d56Sopenharmony_ci:meth:`loop.call_soon_threadsafe` method should be used. Example::
787db96d56Sopenharmony_ci
797db96d56Sopenharmony_ci    loop.call_soon_threadsafe(callback, *args)
807db96d56Sopenharmony_ci
817db96d56Sopenharmony_ciAlmost all asyncio objects are not thread safe, which is typically
827db96d56Sopenharmony_cinot a problem unless there is code that works with them from outside
837db96d56Sopenharmony_ciof a Task or a callback.  If there's a need for such code to call a
847db96d56Sopenharmony_cilow-level asyncio API, the :meth:`loop.call_soon_threadsafe` method
857db96d56Sopenharmony_cishould be used, e.g.::
867db96d56Sopenharmony_ci
877db96d56Sopenharmony_ci    loop.call_soon_threadsafe(fut.cancel)
887db96d56Sopenharmony_ci
897db96d56Sopenharmony_ciTo schedule a coroutine object from a different OS thread, the
907db96d56Sopenharmony_ci:func:`run_coroutine_threadsafe` function should be used. It returns a
917db96d56Sopenharmony_ci:class:`concurrent.futures.Future` to access the result::
927db96d56Sopenharmony_ci
937db96d56Sopenharmony_ci     async def coro_func():
947db96d56Sopenharmony_ci          return await asyncio.sleep(1, 42)
957db96d56Sopenharmony_ci
967db96d56Sopenharmony_ci     # Later in another OS thread:
977db96d56Sopenharmony_ci
987db96d56Sopenharmony_ci     future = asyncio.run_coroutine_threadsafe(coro_func(), loop)
997db96d56Sopenharmony_ci     # Wait for the result:
1007db96d56Sopenharmony_ci     result = future.result()
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ciTo handle signals and to execute subprocesses, the event loop must be
1037db96d56Sopenharmony_cirun in the main thread.
1047db96d56Sopenharmony_ci
1057db96d56Sopenharmony_ciThe :meth:`loop.run_in_executor` method can be used with a
1067db96d56Sopenharmony_ci:class:`concurrent.futures.ThreadPoolExecutor` to execute
1077db96d56Sopenharmony_ciblocking code in a different OS thread without blocking the OS thread
1087db96d56Sopenharmony_cithat the event loop runs in.
1097db96d56Sopenharmony_ci
1107db96d56Sopenharmony_ciThere is currently no way to schedule coroutines or callbacks directly
1117db96d56Sopenharmony_cifrom a different process (such as one started with
1127db96d56Sopenharmony_ci:mod:`multiprocessing`). The :ref:`asyncio-event-loop-methods`
1137db96d56Sopenharmony_cisection lists APIs that can read from pipes and watch file descriptors
1147db96d56Sopenharmony_ciwithout blocking the event loop. In addition, asyncio's
1157db96d56Sopenharmony_ci:ref:`Subprocess <asyncio-subprocess>` APIs provide a way to start a
1167db96d56Sopenharmony_ciprocess and communicate with it from the event loop. Lastly, the
1177db96d56Sopenharmony_ciaforementioned :meth:`loop.run_in_executor` method can also be used
1187db96d56Sopenharmony_ciwith a :class:`concurrent.futures.ProcessPoolExecutor` to execute
1197db96d56Sopenharmony_cicode in a different process.
1207db96d56Sopenharmony_ci
1217db96d56Sopenharmony_ci.. _asyncio-handle-blocking:
1227db96d56Sopenharmony_ci
1237db96d56Sopenharmony_ciRunning Blocking Code
1247db96d56Sopenharmony_ci=====================
1257db96d56Sopenharmony_ci
1267db96d56Sopenharmony_ciBlocking (CPU-bound) code should not be called directly.  For example,
1277db96d56Sopenharmony_ciif a function performs a CPU-intensive calculation for 1 second,
1287db96d56Sopenharmony_ciall concurrent asyncio Tasks and IO operations would be delayed
1297db96d56Sopenharmony_ciby 1 second.
1307db96d56Sopenharmony_ci
1317db96d56Sopenharmony_ciAn executor can be used to run a task in a different thread or even in
1327db96d56Sopenharmony_cia different process to avoid blocking the OS thread with the
1337db96d56Sopenharmony_cievent loop.  See the :meth:`loop.run_in_executor` method for more
1347db96d56Sopenharmony_cidetails.
1357db96d56Sopenharmony_ci
1367db96d56Sopenharmony_ci
1377db96d56Sopenharmony_ci.. _asyncio-logger:
1387db96d56Sopenharmony_ci
1397db96d56Sopenharmony_ciLogging
1407db96d56Sopenharmony_ci=======
1417db96d56Sopenharmony_ci
1427db96d56Sopenharmony_ciasyncio uses the :mod:`logging` module and all logging is performed
1437db96d56Sopenharmony_civia the ``"asyncio"`` logger.
1447db96d56Sopenharmony_ci
1457db96d56Sopenharmony_ciThe default log level is :py:data:`logging.INFO`, which can be easily
1467db96d56Sopenharmony_ciadjusted::
1477db96d56Sopenharmony_ci
1487db96d56Sopenharmony_ci   logging.getLogger("asyncio").setLevel(logging.WARNING)
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_ci
1517db96d56Sopenharmony_ciNetwork logging can block the event loop. It is recommended to use
1527db96d56Sopenharmony_cia separate thread for handling logs or use non-blocking IO. For example,
1537db96d56Sopenharmony_cisee :ref:`blocking-handlers`.
1547db96d56Sopenharmony_ci
1557db96d56Sopenharmony_ci
1567db96d56Sopenharmony_ci.. _asyncio-coroutine-not-scheduled:
1577db96d56Sopenharmony_ci
1587db96d56Sopenharmony_ciDetect never-awaited coroutines
1597db96d56Sopenharmony_ci===============================
1607db96d56Sopenharmony_ci
1617db96d56Sopenharmony_ciWhen a coroutine function is called, but not awaited
1627db96d56Sopenharmony_ci(e.g. ``coro()`` instead of ``await coro()``)
1637db96d56Sopenharmony_cior the coroutine is not scheduled with :meth:`asyncio.create_task`, asyncio
1647db96d56Sopenharmony_ciwill emit a :exc:`RuntimeWarning`::
1657db96d56Sopenharmony_ci
1667db96d56Sopenharmony_ci    import asyncio
1677db96d56Sopenharmony_ci
1687db96d56Sopenharmony_ci    async def test():
1697db96d56Sopenharmony_ci        print("never scheduled")
1707db96d56Sopenharmony_ci
1717db96d56Sopenharmony_ci    async def main():
1727db96d56Sopenharmony_ci        test()
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_ci    asyncio.run(main())
1757db96d56Sopenharmony_ci
1767db96d56Sopenharmony_ciOutput::
1777db96d56Sopenharmony_ci
1787db96d56Sopenharmony_ci  test.py:7: RuntimeWarning: coroutine 'test' was never awaited
1797db96d56Sopenharmony_ci    test()
1807db96d56Sopenharmony_ci
1817db96d56Sopenharmony_ciOutput in debug mode::
1827db96d56Sopenharmony_ci
1837db96d56Sopenharmony_ci  test.py:7: RuntimeWarning: coroutine 'test' was never awaited
1847db96d56Sopenharmony_ci  Coroutine created at (most recent call last)
1857db96d56Sopenharmony_ci    File "../t.py", line 9, in <module>
1867db96d56Sopenharmony_ci      asyncio.run(main(), debug=True)
1877db96d56Sopenharmony_ci
1887db96d56Sopenharmony_ci    < .. >
1897db96d56Sopenharmony_ci
1907db96d56Sopenharmony_ci    File "../t.py", line 7, in main
1917db96d56Sopenharmony_ci      test()
1927db96d56Sopenharmony_ci    test()
1937db96d56Sopenharmony_ci
1947db96d56Sopenharmony_ciThe usual fix is to either await the coroutine or call the
1957db96d56Sopenharmony_ci:meth:`asyncio.create_task` function::
1967db96d56Sopenharmony_ci
1977db96d56Sopenharmony_ci    async def main():
1987db96d56Sopenharmony_ci        await test()
1997db96d56Sopenharmony_ci
2007db96d56Sopenharmony_ci
2017db96d56Sopenharmony_ciDetect never-retrieved exceptions
2027db96d56Sopenharmony_ci=================================
2037db96d56Sopenharmony_ci
2047db96d56Sopenharmony_ciIf a :meth:`Future.set_exception` is called but the Future object is
2057db96d56Sopenharmony_cinever awaited on, the exception would never be propagated to the
2067db96d56Sopenharmony_ciuser code.  In this case, asyncio would emit a log message when the
2077db96d56Sopenharmony_ciFuture object is garbage collected.
2087db96d56Sopenharmony_ci
2097db96d56Sopenharmony_ciExample of an unhandled exception::
2107db96d56Sopenharmony_ci
2117db96d56Sopenharmony_ci    import asyncio
2127db96d56Sopenharmony_ci
2137db96d56Sopenharmony_ci    async def bug():
2147db96d56Sopenharmony_ci        raise Exception("not consumed")
2157db96d56Sopenharmony_ci
2167db96d56Sopenharmony_ci    async def main():
2177db96d56Sopenharmony_ci        asyncio.create_task(bug())
2187db96d56Sopenharmony_ci
2197db96d56Sopenharmony_ci    asyncio.run(main())
2207db96d56Sopenharmony_ci
2217db96d56Sopenharmony_ciOutput::
2227db96d56Sopenharmony_ci
2237db96d56Sopenharmony_ci    Task exception was never retrieved
2247db96d56Sopenharmony_ci    future: <Task finished coro=<bug() done, defined at test.py:3>
2257db96d56Sopenharmony_ci      exception=Exception('not consumed')>
2267db96d56Sopenharmony_ci
2277db96d56Sopenharmony_ci    Traceback (most recent call last):
2287db96d56Sopenharmony_ci      File "test.py", line 4, in bug
2297db96d56Sopenharmony_ci        raise Exception("not consumed")
2307db96d56Sopenharmony_ci    Exception: not consumed
2317db96d56Sopenharmony_ci
2327db96d56Sopenharmony_ci:ref:`Enable the debug mode <asyncio-debug-mode>` to get the
2337db96d56Sopenharmony_citraceback where the task was created::
2347db96d56Sopenharmony_ci
2357db96d56Sopenharmony_ci    asyncio.run(main(), debug=True)
2367db96d56Sopenharmony_ci
2377db96d56Sopenharmony_ciOutput in debug mode::
2387db96d56Sopenharmony_ci
2397db96d56Sopenharmony_ci    Task exception was never retrieved
2407db96d56Sopenharmony_ci    future: <Task finished coro=<bug() done, defined at test.py:3>
2417db96d56Sopenharmony_ci        exception=Exception('not consumed') created at asyncio/tasks.py:321>
2427db96d56Sopenharmony_ci
2437db96d56Sopenharmony_ci    source_traceback: Object created at (most recent call last):
2447db96d56Sopenharmony_ci      File "../t.py", line 9, in <module>
2457db96d56Sopenharmony_ci        asyncio.run(main(), debug=True)
2467db96d56Sopenharmony_ci
2477db96d56Sopenharmony_ci    < .. >
2487db96d56Sopenharmony_ci
2497db96d56Sopenharmony_ci    Traceback (most recent call last):
2507db96d56Sopenharmony_ci      File "../t.py", line 4, in bug
2517db96d56Sopenharmony_ci        raise Exception("not consumed")
2527db96d56Sopenharmony_ci    Exception: not consumed
253