Lesson 19: Asynchronous Programming (async/await)

How Python handles concurrency and non‑blocking operations

What Is Asynchronous Programming?

Asynchronous programming allows your program to perform other tasks while waiting for slow operations to finish, such as network requests, file I/O, or timers. Instead of blocking execution, Python can switch between tasks efficiently.

The asyncio Module

Python’s built‑in asyncio module provides tools for writing asynchronous code using async and await.

Defining an Async Function

import asyncio

async def greet():
    print("Hello!")

Running an Async Function

asyncio.run(greet())

Using await

await pauses the function until the awaited task completes:

async def wait_and_print():
    await asyncio.sleep(2)
    print("Done waiting!")

Combining Multiple Tasks

You can run tasks concurrently:

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

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

asyncio.run(main())

Creating Tasks Manually

async def main():
    t1 = asyncio.create_task(task("A", 2))
    t2 = asyncio.create_task(task("B", 3))

    await t1
    await t2

When to Use Async Programming

When NOT to Use Async

Real‑World Example: Fetching Multiple URLs

import asyncio
import aiohttp

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:
        results = await asyncio.gather(*(fetch(session, u) for u in urls))
        print(results)

asyncio.run(main())

Why Async Matters

Next Steps

Now that you understand asynchronous programming, you're ready to explore how to write automated tests in Lesson 20: Introduction to Testing (unittest).

← Back to Lesson Index