- Published on
Python Async/Await - Write Non-Blocking Code Like a Pro
- Authors

- Name
- Sanjeev Sharma
- @webcoderspeed1
Introduction
Async programming in Python is no longer just for experts. With asyncio, async/await syntax, and modern libraries like httpx and aiofiles, you can write highly performant, non-blocking code with ease.
If you've ever noticed your Python script sitting idle while waiting for a database response or an API call, this guide is for you.
- What is Asynchronous Programming?
- The Basics: async and await
- Running Multiple Tasks Concurrently
- Making Async HTTP Requests with httpx
- Async File I/O with aiofiles
- asyncio.create_task() for Background Tasks
- Common Mistakes to Avoid
- When to Use Async (and When NOT to)
- Conclusion
What is Asynchronous Programming?
In synchronous code, tasks run one after another. If task A takes 5 seconds, task B waits.
In asynchronous code, while task A is waiting (e.g., for a network response), Python switches to run task B. This makes your program significantly faster for I/O-bound tasks.
Synchronous: [Task A - 5s] [Task B - 3s] = 8 seconds total
Asynchronous: [Task A waits...] + [Task B runs] = ~5 seconds total
The Basics: async and await
import asyncio
async def say_hello():
print("Hello...")
await asyncio.sleep(2) # Non-blocking sleep
print("...World!")
asyncio.run(say_hello())
async defdefines a coroutine functionawaitsuspends execution until the awaited task completesasyncio.run()is the entry point to run your async code
Running Multiple Tasks Concurrently
The real power of async comes when you run multiple tasks at the same time:
import asyncio
async def fetch_data(name, delay):
print(f"Fetching {name}...")
await asyncio.sleep(delay)
print(f"{name} done!")
return f"{name} data"
async def main():
# Run all tasks concurrently using gather
results = await asyncio.gather(
fetch_data("Users", 3),
fetch_data("Products", 1),
fetch_data("Orders", 2),
)
print(results)
asyncio.run(main())
Output:
Fetching Users...
Fetching Products...
Fetching Orders...
Products done!
Orders done!
Users done!
['Users data', 'Products data', 'Orders data']
All three ran concurrently! Total time: ~3 seconds instead of 6.
Making Async HTTP Requests with httpx
The most common use case for async is HTTP requests. Use httpx instead of requests:
pip install httpx
import asyncio
import httpx
async def fetch_github_user(username):
async with httpx.AsyncClient() as client:
response = await client.get(f"https://api.github.com/users/{username}")
return response.json()
async def main():
users = await asyncio.gather(
fetch_github_user("torvalds"),
fetch_github_user("gvanrossum"),
fetch_github_user("yyx990803"),
)
for user in users:
print(f"{user['name']} - {user['public_repos']} repos")
asyncio.run(main())
Async File I/O with aiofiles
pip install aiofiles
import asyncio
import aiofiles
async def read_file(path):
async with aiofiles.open(path, mode='r') as f:
content = await f.read()
return content
async def write_file(path, content):
async with aiofiles.open(path, mode='w') as f:
await f.write(content)
async def main():
await write_file("output.txt", "Hello from async file I/O!")
content = await read_file("output.txt")
print(content)
asyncio.run(main())
asyncio.create_task() for Background Tasks
import asyncio
async def background_job():
await asyncio.sleep(5)
print("Background job done!")
async def main():
task = asyncio.create_task(background_job())
# Do other work while the background task runs
print("Doing other stuff...")
await asyncio.sleep(1)
print("Still working...")
await task # Wait for background task to finish
asyncio.run(main())
Common Mistakes to Avoid
1. Blocking the event loop
# ❌ BAD - blocks the event loop
import time
async def bad_function():
time.sleep(5) # This blocks everything!
# ✅ GOOD - non-blocking
async def good_function():
await asyncio.sleep(5)
2. Forgetting await
# ❌ BAD - creates a coroutine but never runs it
async def main():
result = fetch_data() # Missing await!
# ✅ GOOD
async def main():
result = await fetch_data()
When to Use Async (and When NOT to)
Use async for:
- Making HTTP requests
- Database queries (with async drivers like
asyncpg,motor) - Reading/writing files
- WebSockets
Don't use async for:
- CPU-heavy tasks (use
multiprocessinginstead) - Simple scripts that don't do I/O
- Code that uses only sync libraries
Conclusion
Async Python is one of the most powerful skills you can add to your toolkit. With asyncio, httpx, and aiofiles, writing fast, concurrent code has never been easier. Start small — convert one slow API call to async — and watch your performance improve dramatically.