Python Guide Sidebar

Coroutines in Python: A Complete Guide

Coroutines in Python are a fundamental part of Python’s asynchronous programming paradigm. They provide a powerful way to handle concurrency, enabling developers to write efficient, non-blocking code. In this guide, we’ll dive into the basics, explore how coroutines work, provide examples, discuss best practices, highlight advantages and disadvantages, and share common interview questions with answers.

Coroutines in Python
Coroutines in Python

What Are Coroutines in Python?

Coroutines are specialized Python functions designed for asynchronous execution. Unlike regular functions that produce a result and terminate, coroutines can pause execution, yield control, and later resume from where they stopped.

Why Use Coroutines in Python?

  • Asynchronous Programming: Handle multiple tasks without blocking the main thread.
  • Concurrency: Run multiple operations concurrently without requiring multi threading.
  • Efficiency: Ideal for I/O-bound operations like file handling, network requests, and database queries.

Key Differences Between Functions, Generators, and Coroutines

AspectFunctionsGeneratorsCoroutines
ExecutionExecutes once and returnsYields values iterativelyPauses and resumes
Use CaseGeneral-purpose logicIterative data processingAsynchronous operations
Syntaxdefdef + yieldasync def
Coroutines

How to Use Coroutines in Python

1. Creating a Coroutine

Define a coroutine using the async def keyword.

async def my_coroutine():
    print("Coroutine started")
    await asyncio.sleep(1)  # Simulate asynchronous operation
    print("Coroutine ended")
2.Running a Coroutine

Coroutines must be executed within an event loop. Use the asyncio.run() function.

import asyncio

async def greet():
    print("Hello, Coroutine!")
    await asyncio.sleep(1)
    print("Goodbye, Coroutine!")

# Instead of using loop.run_until_complete(), schedule the coroutine as a task
asyncio.create_task(greet())
3.Using await

The await keyword pauses coroutine execution until the awaited task is complete.

import asyncio

async def fetch_data():
    print("Fetching data...")
    await asyncio.sleep(2)  # Simulate I/O operation
    print("Data fetched")
4.Combining Coroutines with asyncio.gather()

Run multiple coroutines concurrently and wait for all to complete.

import asyncio

async def task1():
    print("Task 1 started")
    await asyncio.sleep(1)
    print("Task 1 finished")

async def task2():
    print("Task 2 started")
    await asyncio.sleep(2)
    print("Task 2 finished")

# Run coroutines concurrently
asyncio.run(asyncio.gather(task1(), task2()))

Real-World Examples of Coroutines in Python

1. Network Requests with Coroutines

Efficiently handle multiple HTTP requests using coroutines.

import asyncio
import aiohttp

async def fetch_url(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            print(f"Fetched {url} with status {response.status}")

urls = ["https://example.com", "https://python.org", "https://async.io"]

async def main():
    tasks = [fetch_url(url) for url in urls]
    await asyncio.gather(*tasks)

asyncio.run(main())
2.Database Access

Coroutines can interact with asynchronous database libraries like asyncpg.

import asyncpg
import asyncio

async def fetch_users():
    conn = await asyncpg.connect(user='user', password='password', database='testdb', host='127.0.0.1')
    rows = await conn.fetch('SELECT * FROM users')
    for row in rows:
        print(row)
    await conn.close()

asyncio.run(fetch_users())

Advantages of Coroutines

  1. Non-Blocking: Perfect for I/O-bound operations.
  2. Lightweight: Use less memory compared to threads.
  3. Efficient: Handle thousands of concurrent tasks in a single thread.
  4. Simple Syntax: The async and await keywords make code readable and maintainable.

Disadvantages of Coroutines

  1. Learning Curve: Understanding event loops and asynchronous patterns can be challenging for beginners.
  2. Debugging: Debugging asynchronous code may be harder than synchronous code.
  3. Limited CPU-Bound Tasks: Not suitable for tasks requiring heavy computation.

Conclusion

Coroutines in Python are a game-changer for building modern, scalable, and efficient applications. By mastering their usage and combining them with libraries like asyncio, developers can unlock the full potential of asynchronous programming.

Let’s Check ! Click Me

Interview Questions

1. What are coroutines in Python?

Company: Google
Answer: Coroutines are Python functions defined with async def that allow pausing and resuming execution, enabling asynchronous programming.

2. How does await work in a coroutine?

Company: Microsoft
Answer: The await keyword pauses the coroutine until the awaited task is completed, allowing other tasks in the event loop to run.

3. How do coroutines differ from threads?

Company: Amazon
Answer: Coroutines run in a single thread and use an event loop to manage concurrency, whereas threads require system-level resources and can run in parallel.

4. Explain the purpose of asyncio.gather().

Company: Meta (Facebook)
Answer: asyncio.gather() runs multiple coroutines concurrently and waits for all of them to complete.

5. What are some common libraries for asynchronous programming in Coroutines in Python ?

Company: Oracle
Answer: Popular libraries include asyncio, aiohttp for HTTP requests, and asyncpg for database access.

QUIZZES

Coroutines Quiz