πŸ’‘ Advanced Python Concepts
Estimated reading: 4 minutes 21 views

πŸ”„ Python Coroutines Explained – asyncio, await, gather Examples

🧲 Introduction – Why Use Coroutines in Python?

Modern Python applicationsβ€”like web servers, real-time APIs, and event-driven systemsβ€”demand non-blocking, asynchronous behavior. Enter coroutines.

Coroutines in Python allow you to:

  • Pause and resume execution
  • Run concurrent tasks without threads
  • Build highly responsive, non-blocking applications

Coroutines are the foundation of Python’s async/await syntax introduced in Python 3.5+.

🎯 In this guide, you’ll learn:

  • What coroutines are and how they differ from generators
  • How to define and run async coroutines
  • Real-world examples using asyncio
  • Best practices and when to use coroutines over threads

βœ… What Is a Coroutine?

A coroutine is a special function declared with async def that can pause execution with await and resume later.

import asyncio

async def greet():
    print("Hello")
    await asyncio.sleep(1)
    print("World")

πŸ“Œ You can only await inside an async def function.


▢️ How to Run a Coroutine

async def main():
    await greet()

asyncio.run(main())

βœ… Output:

Hello
(wait 1 second)
World

πŸ’‘ asyncio.run() is the recommended way to start the event loop in Python 3.7+.


πŸ” Coroutines vs Generators

FeatureGeneratorsCoroutines (async)
Keyworddef, yieldasync def, await
Use CaseLazy iterationAsynchronous programming
Pause Withyieldawait
SchedulerManual or loopsasyncio event loop

⏱️ Example – Simulate Concurrent Tasks

import asyncio

async def task(name, delay):
    print(f"{name} started")
    await asyncio.sleep(delay)
    print(f"{name} completed")

async def main():
    await asyncio.gather(
        task("Task 1", 2),
        task("Task 2", 1)
    )

asyncio.run(main())

βœ… Output:

Task 1 started  
Task 2 started  
Task 2 completed  
Task 1 completed

πŸ“Œ Coroutines run concurrently but not in parallel (no threads involved).


πŸ’¬ Awaitable Objects

You can await on:

  • Coroutines (async def)
  • asyncio.sleep, asyncio.open_connection, etc.
  • Objects implementing __await__()

🧱 Create Custom Awaitables

class Wait:
    def __await__(self):
        yield from asyncio.sleep(1).__await__()

async def use_wait():
    print("Waiting...")
    await Wait()
    print("Done")

asyncio.run(use_wait())

βœ… You can define your own awaitable classes for advanced control.


🧰 Real-World Use Case – Async HTTP Requests

import aiohttp
import asyncio

async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def main():
    html = await fetch("https://example.com")
    print(html[:100])

asyncio.run(main())

βœ… No threads, no blockingβ€”ideal for I/O-heavy workloads like web scrapers or APIs.


❗ Coroutines Are Not Threads

FeatureCoroutineThread
Switch TimeExplicit (await)Preemptive (by OS)
MemoryLightweightHeavier
ParallelismNo (single-threaded)Yes (true parallel threads)
Best ForI/O-bound tasksCPU-bound or parallel tasks

πŸ“˜ Best Practices

βœ… Do This❌ Avoid This
Use asyncio.run() to start your appNesting asyncio.run() inside coroutines
Use await for non-blocking I/OCalling blocking code inside coroutines
Use asyncio.gather() for concurrent tasksAwaiting tasks one-by-one unnecessarily
Use libraries like aiohttp, aiomysqlMixing async and sync I/O

πŸ“Œ Summary – Recap & Next Steps

Python coroutines enable non-blocking, asynchronous programming using modern syntax (async/await). They’re powerful tools for building scalable, I/O-bound applications.

πŸ” Key Takeaways:

  • βœ… async def defines a coroutine
  • βœ… Use await to pause execution
  • βœ… Use asyncio.run() to launch coroutines
  • βœ… Coroutines are lightweight and ideal for I/O-bound tasks
  • ❌ Don’t use coroutines for CPU-bound tasksβ€”use multiprocessing instead

βš™οΈ Real-World Relevance:
Used in async web frameworks (FastAPI, Sanic), chatbots, IoT systems, web scrapers, and real-time APIs.


❓ FAQ – Python Coroutines

❓ What’s the difference between a coroutine and a regular function?

βœ… Coroutines are declared with async def and use await to pause and resume.

❓ Can coroutines run in parallel?

❌ No. Coroutines run concurrently on the same thread. Use threads or processes for true parallelism.

❓ How do I call a coroutine?

βœ… Use await coroutine() inside another coroutine, or asyncio.run() at the top level.

❓ Can I use await outside of a function?

❌ No. await must be used inside an async def function.

❓ Are coroutines faster than threads?

βœ… For I/O-bound tasks, yes. They use less memory and have lower overhead.


Share Now :

Leave a Reply

Your email address will not be published. Required fields are marked *

Share

Python Coroutines

Or Copy Link

CONTENTS
Scroll to Top