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