🧠 Introduction
In modern Python programming, writing efficient and scalable code often means dealing with asynchronous operations. Whether you’re building a web server, scraping websites, or handling thousands of API requests, coroutines are the secret weapon behind Python’s asynchronous magic.
This article will walk you through:
- What coroutines are in Python
- How they differ from functions and generators
- How to use
async
/await
syntax - Real-world examples and best practices
🔍 What Is a Coroutine?
A coroutine is a special kind of function that can pause and resume its execution. In Python, coroutines are used in asynchronous programming, which allows tasks to be performed without blocking the entire program.
A coroutine is declared with
async def
and is executed usingawait
.
Coroutines allow your code to remain responsive and efficient, especially during I/O-bound tasks like network requests or file operations.
✅ Why Use Coroutines?
- 🚀 Non-blocking execution
- 🔄 Concurrency with a single thread
- 📈 Improved performance for I/O tasks
- 🔋 Lower resource usage compared to threads/processes
🧪 Coroutine Basics: async
and await
Here’s how you define and use a coroutine:
import asyncio
async def greet():
print("Hello")
await asyncio.sleep(1)
print("World")
# Running the coroutine
asyncio.run(greet())
Explanation:
async def greet()
defines an asynchronous coroutine.await asyncio.sleep(1)
pauses the coroutine for 1 second without blocking other coroutines.
🔄 Running Multiple Coroutines Concurrently
The real power of coroutines is visible when running multiple tasks together.
import asyncio
async def download_file(file_id):
print(f"Downloading {file_id}")
await asyncio.sleep(2)
print(f"Finished {file_id}")
async def main():
tasks = [
download_file(1),
download_file(2),
download_file(3)
]
await asyncio.gather(*tasks)
asyncio.run(main())
This runs all three download_file
coroutines concurrently, using the same thread and without blocking.
🧵 Coroutines vs Threads
Feature | Coroutines (asyncio ) | Threads |
---|---|---|
Threading Required | ❌ No | ✅ Yes |
Memory Footprint | 🟢 Low | 🔴 High (1 thread per task) |
Suitable For | I/O-bound tasks | I/O and some CPU tasks |
True Parallelism | ❌ No (single-threaded) | ✅ Limited by GIL in CPython |
Syntax | async / await | threading.Thread |
⚠️ Things You Can and Can’t await
You can await
any awaitable object. These include:
- Coroutines (declared with
async def
) asyncio.sleep
,asyncio.open_connection
, etc.- Custom objects that implement
__await__()
You can’t await
normal functions or blocking I/O (like time.sleep()
).
❌ Bad:
await time.sleep(1)
✅ Good:
await asyncio.sleep(1)
📚 Real-World Use Cases
1. Web Servers (FastAPI, AIOHTTP)
from fastapi import FastAPI
import asyncio
app = FastAPI()
@app.get("/delay")
async def delayed_response():
await asyncio.sleep(2)
return {"message": "Done!"}
2. Web Scraping
import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
urls = ["https://example.com", "https://python.org"]
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks)
print(results)
asyncio.run(main())
🧠 Best Practices
- ✅ Always use
asyncio.run()
to start the main coroutine (Python 3.7+). - ✅ Use
await
only insideasync def
. - ❌ Avoid blocking functions like
time.sleep()
orrequests.get()
inside coroutines — they will freeze the event loop. - ✅ Use third-party async libraries like
aiohttp
for non-blocking I/O.
🧩 Advanced: Creating Your Own Coroutine
You can create a coroutine manually using a generator-style syntax (not recommended unless you’re building libraries):
def manual_coroutine():
yield
# But prefer using:
async def async_coroutine():
await asyncio.sleep(1)
🔚 Conclusion
Coroutines are a cornerstone of asynchronous programming in Python. They let you write non-blocking, concurrent code that is clean, readable, and performant — especially for I/O-bound tasks.
By mastering async
and await
, you unlock the full potential of modern Python for building APIs, bots, scrapers, and event-driven systems.
Leave a Reply