Async/Await in Python: A Beginner-Friendly Guide with Real Examples

Master Python’s async and await with simple explanations, hands-on examples, and practical use cases that finally make it all click.

Async/Await in Python: A Beginner-Friendly Guide with Real Examples
Photo by Heidi Fin on Unsplash

Async doesn’t have to be intimidating — once you “get it,” it’s a game changer.

Async/Await in Python: A Beginner-Friendly Guide with Real Examples

Introduction: “Why Does Everyone Keep Talking About Async?”

If you’ve been coding in Python for a while, chances are you’ve run into the words async, await, or coroutines — and maybe quickly backed away.

You’re not alone.

Many developers (even experienced ones) find Python’s async model confusing at first glance. The syntax is different, the control flow feels “non-linear,” and the concept of coroutines sounds like something out of a computer science thesis.

But here’s the truth: async/await in Python isn’t that scary — and it can drastically improve how you write I/O-bound programs.

This article is your guide to demystifying async in Python. We’ll break it down step by step, with real-world examples and practical insights that’ll make you say, “Ah, now I get it.”


What Is Async in Python, Really?

Let’s start with the problem.

Imagine you’re writing a script that makes multiple HTTP requests:

import requests 
 
def fetch_data(): 
    response = requests.get("https://api.example.com/data") 
    return response.json()

If you call this function multiple times in a loop, each request blocks until the previous one finishes.

That’s fine for one or two calls. But what if you need to fetch hundreds of URLs? Your script will crawl.

Async I/O to the rescue.

Instead of blocking while waiting for a response, async allows your program to do something else while waiting — all within the same thread.

Synchronous vs Asynchronous: A Visual Metaphor

Here’s a metaphor:

  • Synchronous Python is like standing in line at the DMV. Each person is served one at a time. You can’t move until the person ahead of you is done.
  • Asynchronous Python is like ordering food at a restaurant with a buzzer. You place your order and sit down. When your food’s ready, they buzz you. Meanwhile, you can chat, scroll your phone, or help others.

Async lets you wait without waiting.


Key Concepts: async def, await, and the Event Loop

Let’s break down the three most important concepts:

1. async def — Defining a Coroutine

In async Python, functions defined with async def are coroutines. They’re special functions that can be paused and resumed.

async def say_hello(): 
    print("Hello")

Calling say_hello() doesn’t run it immediately — it returns a coroutine object. You need to run or await it.

2. await — Pausing Until Something’s Done

The await keyword pauses your coroutine until another coroutine finishes.

import asyncio 
 
async def main(): 
    await say_hello()

You can only use await inside an async def function.

3. The Event Loop — Async’s Secret Sauce

The event loop is like a task manager. It runs in the background, monitoring tasks and resuming them when they’re ready.

You can start it using:

asyncio.run(main())

A Real Example: Making Multiple API Calls Concurrently

Here’s where async really shines. Let’s fetch multiple URLs:

Without Async (Slow & Blocking):

import requests 
 
urls = ["https://httpbin.org/delay/2"] * 5 
 
for url in urls: 
    response = requests.get(url) 
    print(response.status_code)

This takes ~10 seconds (2s per request × 5).

With Async (Much Faster!):

import asyncio 
import aiohttp 
 
async def fetch(session, url): 
    async with session.get(url) as response: 
        print(response.status) 
        return await response.text() 
 
async def main(): 
    urls = ["https://httpbin.org/delay/2"] * 5 
    async with aiohttp.ClientSession() as session: 
        tasks = [fetch(session, url) for url in urls] 
        await asyncio.gather(*tasks) 
 
asyncio.run(main())

This takes ~2 seconds total, because all five requests happen concurrently.

When Should You Use Async in Python?

Async isn’t always the right tool. Use it when your program:

Spends time waiting — like making HTTP requests, reading from disk, or querying a database.

Does a lot of CPU-bound work — like crunching numbers or processing large images. For that, use multiprocessing or threads.

Good use cases:

  • Web scraping multiple sites
  • Building APIs (e.g., FastAPI)
  • Real-time bots or chat apps
  • File uploads/downloads
  • Periodic background tasks

Common Gotchas for Beginners

Even though async is powerful, it’s easy to trip up. Here are some common pitfalls:

  • Mixing sync and async functions: You can’t just await a regular function.
  • Blocking the event loop: Avoid using time.sleep() inside async code. Use await asyncio.sleep().
  • Forgetting to await: Calling an async function without await returns a coroutine object — it won’t run until awaited.

Bonus: Async Sleep vs Sync Sleep

Let’s compare two versions of “sleeping”:

Synchronous Sleep

import time 
 
def blocking(): 
    time.sleep(2) 
    print("Done")

This blocks the entire thread.

Asynchronous Sleep

import asyncio 
 
async def non_blocking(): 
    await asyncio.sleep(2) 
    print("Done")

This lets other tasks run while sleeping — way more efficient in async programs.

How I Personally Use Async in My Projects

In one of my recent side projects — a dashboard that monitors multiple APIs — async helped me reduce a 20-second data refresh down to just 3 seconds.

Instead of waiting for each API to respond one by one, I used aiohttp to fire them all at once. The result? A snappy UI and much happier users.


Final Thoughts: Async Isn’t Magic — But It Feels Like It

Once you understand the core concepts of async/await in Python, it opens up a new world of possibilities.

You’ll write faster scripts, smoother APIs, and more responsive apps — all with fewer threads, less memory, and better scalability.

So don’t fear the event loop. Embrace it.

And the next time someone says “just use async,” you’ll smile — because now, you actually know what that means.


Mastering async is like upgrading your Python brain — once you see the speed boost, there’s no going back.

Photo by Javier Allegue Barros on Unsplash