Debugging Asyncio Applications
Свайпніть щоб показати меню
Async bugs are harder to track than synchronous ones. A forgotten await, a blocking call inside a coroutine, or a task that silently fails can all cause subtle, hard-to-reproduce issues. Asyncio provides several built-in tools to catch these problems early.
Debug Mode
Enable asyncio's debug mode to surface common mistakes that are silent in production:
1234567891011import asyncio import nest_asyncio nest_asyncio.apply() # Enabling debug mode to catch slow callbacks and missing awaits async def main(): await asyncio.sleep(0.1) print("Running in debug mode") asyncio.run(main(), debug=True)
In debug mode, asyncio:
- Warns about coroutines that were created but never awaited;
- Logs callbacks that take longer than 100ms (slow callback detection);
- Enables more detailed
repr()output for tasks and futures.
Detecting a Forgotten await
The most common asyncio mistake is calling an async function without await. The coroutine object is created but never executed:
12345678910111213141516171819import asyncio import warnings import nest_asyncio nest_asyncio.apply() async def fetch_data(): await asyncio.sleep(0.1) return "data" # Forgetting await – coroutine is never executed async def main(): result = fetch_data() # Missing await print(result) # <coroutine object fetch_data at 0x...> # Converting the warning to an error so it cannot be missed warnings.filterwarnings("error", category=RuntimeWarning) asyncio.run(main(), debug=True)
Python emits RuntimeWarning: coroutine 'fetch_data' was never awaited. Running with warnings.filterwarnings("error") converts this warning into an exception, making it impossible to miss.
Inspecting Running Tasks
Use asyncio.all_tasks() to see what is currently running – useful for identifying stuck or leaked tasks:
12345678910111213141516171819202122232425262728import asyncio import httpx import nest_asyncio nest_asyncio.apply() # Inspecting all running tasks mid-execution async def fetch_post(client, post_id): response = await client.get( f"https://jsonplaceholder.typicode.com/posts/{post_id}" ) return response.json()["title"] async def main(): async with httpx.AsyncClient() as client: tasks = [ asyncio.create_task(fetch_post(client, post_id)) for post_id in range(1, 4) ] print(f"Running tasks: {len(asyncio.all_tasks())}") results = await asyncio.gather(*tasks) for result in results: print(result) asyncio.run(main())
Tracing Slow Callbacks
A slow synchronous call inside a coroutine blocks the event loop without raising any error. Debug mode catches it:
12345678910111213141516import asyncio import time import nest_asyncio nest_asyncio.apply() # Detecting a slow callback with a custom threshold async def main(): loop = asyncio.get_event_loop() loop.slow_callback_duration = 0.05 # Warning threshold: 50ms await asyncio.sleep(0) time.sleep(0.2) # Blocking call – triggers a slow callback warning await asyncio.sleep(0) asyncio.run(main(), debug=True)
Common Asyncio Bugs and Fixes
Дякуємо за ваш відгук!
Запитати АІ
Запитати АІ
Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат
Debugging Asyncio Applications
Async bugs are harder to track than synchronous ones. A forgotten await, a blocking call inside a coroutine, or a task that silently fails can all cause subtle, hard-to-reproduce issues. Asyncio provides several built-in tools to catch these problems early.
Debug Mode
Enable asyncio's debug mode to surface common mistakes that are silent in production:
1234567891011import asyncio import nest_asyncio nest_asyncio.apply() # Enabling debug mode to catch slow callbacks and missing awaits async def main(): await asyncio.sleep(0.1) print("Running in debug mode") asyncio.run(main(), debug=True)
In debug mode, asyncio:
- Warns about coroutines that were created but never awaited;
- Logs callbacks that take longer than 100ms (slow callback detection);
- Enables more detailed
repr()output for tasks and futures.
Detecting a Forgotten await
The most common asyncio mistake is calling an async function without await. The coroutine object is created but never executed:
12345678910111213141516171819import asyncio import warnings import nest_asyncio nest_asyncio.apply() async def fetch_data(): await asyncio.sleep(0.1) return "data" # Forgetting await – coroutine is never executed async def main(): result = fetch_data() # Missing await print(result) # <coroutine object fetch_data at 0x...> # Converting the warning to an error so it cannot be missed warnings.filterwarnings("error", category=RuntimeWarning) asyncio.run(main(), debug=True)
Python emits RuntimeWarning: coroutine 'fetch_data' was never awaited. Running with warnings.filterwarnings("error") converts this warning into an exception, making it impossible to miss.
Inspecting Running Tasks
Use asyncio.all_tasks() to see what is currently running – useful for identifying stuck or leaked tasks:
12345678910111213141516171819202122232425262728import asyncio import httpx import nest_asyncio nest_asyncio.apply() # Inspecting all running tasks mid-execution async def fetch_post(client, post_id): response = await client.get( f"https://jsonplaceholder.typicode.com/posts/{post_id}" ) return response.json()["title"] async def main(): async with httpx.AsyncClient() as client: tasks = [ asyncio.create_task(fetch_post(client, post_id)) for post_id in range(1, 4) ] print(f"Running tasks: {len(asyncio.all_tasks())}") results = await asyncio.gather(*tasks) for result in results: print(result) asyncio.run(main())
Tracing Slow Callbacks
A slow synchronous call inside a coroutine blocks the event loop without raising any error. Debug mode catches it:
12345678910111213141516import asyncio import time import nest_asyncio nest_asyncio.apply() # Detecting a slow callback with a custom threshold async def main(): loop = asyncio.get_event_loop() loop.slow_callback_duration = 0.05 # Warning threshold: 50ms await asyncio.sleep(0) time.sleep(0.2) # Blocking call – triggers a slow callback warning await asyncio.sleep(0) asyncio.run(main(), debug=True)
Common Asyncio Bugs and Fixes
Дякуємо за ваш відгук!