Using Asyncio in Python
Asynchronous programming in Python allows you to write code that doesn’t block while waiting for external operations like network calls or disk I/O. Using async
and await
, you can speed up your applications without using threads or complex concurrency models.
1. What Is Async in Python?
# Normal (blocking) example
import time
def task():
time.sleep(1)
print("Done")
task()
print("All tasks done.")
The above code waits before printing anything. With async, we can avoid this blocking behavior.
2. Basic Async/Await Syntax
import asyncio
async def say_hello():
print("Hello")
await asyncio.sleep(1)
print("World")
asyncio.run(say_hello())
3. Running Multiple Coroutines
import asyncio
async def greet(name):
print(f"Hi {name}")
await asyncio.sleep(1)
print(f"Bye {name}")
async def main():
await asyncio.gather(
greet("Alice"),
greet("Bob"),
greet("Charlie")
)
asyncio.run(main())
4. Using Async with HTTP Requests (aiohttp)
import asyncio
import aiohttp
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
print(f"{url} - {response.status}")
urls = ["https://example.com", "https://python.org", "https://httpbin.org/get"]
async def main():
tasks = [fetch(url) for url in urls]
await asyncio.gather(*tasks)
asyncio.run(main())
5. Creating a Simple Async Test
import asyncio
import unittest
class AsyncTest(unittest.IsolatedAsyncioTestCase):
async def test_async_function(self):
async def slow_add(a, b):
await asyncio.sleep(1)
return a + b
result = await slow_add(3, 4)
self.assertEqual(result, 7)
if __name__ == "__main__":
unittest.main()
6. Custom Sleep Loops
import asyncio
async def count():
for i in range(5):
print(f"Count {i}")
await asyncio.sleep(0.5)
asyncio.run(count())
7. Handling Exceptions in Async
import asyncio
async def risky_task():
raise ValueError("Oops!")
async def main():
try:
await risky_task()
except ValueError as e:
print(f"Caught: {e}")
asyncio.run(main())
8. Writing Async Context Managers
class AsyncResource:
async def __aenter__(self):
print("Starting")
return self
async def __aexit__(self, exc_type, exc, tb):
print("Cleaning up")
async def use_resource():
async with AsyncResource():
print("Using resource")
asyncio.run(use_resource())
9. Async Tips
# Only use await inside async def
# Don't block the event loop with time.sleep()
# Use asyncio.sleep() instead
# For CPU-bound tasks, consider multiprocessing instead of asyncio
10. When Not to Use Async
# Async is great for:
# - I/O-bound operations
# - Network tasks
# - Waiting for data
# Async is NOT ideal for:
# - Heavy CPU tasks
# - Simple scripts that don’t wait for anything