← Back to list

Why Learning Async Python Completely Changed How I Build Modern Backend Systems

After years of writing synchronous applications, I finally understood why nearly every high-performance Python backend relies on…

Maximilian Oliver in Top Python Libraries · 2026-07-05 11:19 · 0 claps · 4.9 min read paywalled
#python #python-programming #asynchronous-programming #backend-development #python-tips
Open on Medium ↗
Wiki topics: EDU · Education & Learning 💻 · Programming 🌐 · Web Development

Why Learning Async Python Completely Changed How I Build Modern Backend Systems

After years of writing synchronous applications, I finally understood why nearly every high-performance Python backend relies on asynchronous programming — and it wasn’t because async is faster, but because it wastes far less time waiting.

If there’s one topic that confused me more than anything else when I started writing backend applications, it was asynchronous programming.

I understood threads.

I understood processes.

But async and await felt...different.

The examples I found online were usually too simple to explain why asynchronous programming mattered, or too complicated to be useful.

Everything clicked the moment I stopped thinking about CPU speed and started thinking about waiting.

Backend applications don’t spend most of their time doing calculations.

They spend most of their time waiting.

Waiting for databases.

Waiting for APIs.

Waiting for users.

Waiting for files.

Waiting for cloud services.

Once I realized that, Async Python suddenly became one of the most valuable tools in my development toolkit.

Here’s what I learned while building modern backend systems.

1. The Biggest Performance Problem Usually Isn’t Your Code

When developers talk about optimization, they often focus on algorithms.

Should we reduce complexity?

Should we cache results?

Should we optimize loops?

Those are important questions.

But for web applications, the biggest bottleneck is usually something much simpler.

Waiting.

Imagine an API endpoint that performs these operations.

  • Fetch user information
  • Query the orders database
  • Call a payment service
  • Retrieve product recommendations
  • Read files from cloud storage

Each operation spends most of its lifetime waiting on another system.

The CPU is almost idle.

A synchronous application simply waits for each operation to finish before starting the next.

Database ----------- 400 ms
↓
Payment API -------- 600 ms
↓
Recommendation API - 700 ms
↓
Cloud Storage ------ 500 ms
↓
Total = 2.2 seconds

Now imagine running those requests at the same time.

Database ----------- 400 ms
Payment API -------- 600 ms
Recommendation API - 700 ms
Cloud Storage ------ 500 ms
↓
Total ≈ 700 ms

Nothing became faster.

You simply stopped waiting unnecessarily.

That is exactly what asynchronous programming enables.

2. Understanding the Event Loop Was the Turning Point

The phrase event loop sounded intimidating for years.

In reality, I now think of it as an efficient project manager.

Instead of watching one employee complete an entire task before assigning another, the manager keeps everyone busy.

When one task pauses to wait for I/O, another immediately starts.

Python does the same thing.

import asyncio
import random
async def fetch_service(name: str, delay: int):
    print(f"Starting {name}")
    await asyncio.sleep(delay)
    print(f"{name} finished")
    return {
        "service": name,
        "delay": delay
    }

async def main():
    services = [
        fetch_service("Database", 2),
        fetch_service("Redis", 1),
        fetch_service("Payments", 3),
        fetch_service("Analytics", 2)
    ]
    results = await asyncio.gather(*services)
    print(results)

asyncio.run(main())

Every task gets an opportunity to run.

Whenever one pauses, another continues.

Once I understood that idea, async code stopped feeling magical.

3. Async Isn’t About Making Everything Concurrent

One mistake I made early on was trying to convert every function into an async function.

That created unnecessary complexity.

Some work benefits from async.

Some doesn’t.

A useful rule I now follow is surprisingly simple.

If the task spends time waiting, consider async.

If the task spends time computing, async probably won’t help.

For example:

Excellent candidates:

  • API requests
  • Database queries
  • File uploads
  • Downloads
  • WebSockets
  • Streaming responses
  • Cloud storage

Poor candidates:

  • Image processing
  • Data compression
  • Machine learning training
  • Video rendering
  • Mathematical simulations

Understanding that distinction saved me from overengineering several projects.

4. Building Multiple API Requests Suddenly Became Simple

Modern backend services rarely depend on one external API.

Instead, one request often triggers several others.

Here’s an example that loads information from multiple services simultaneously.

import asyncio
import httpx
BASE_URL = "https://jsonplaceholder.typicode.com"
async def fetch(endpoint: str, client: httpx.AsyncClient):
    response = await client.get(f"{BASE_URL}/{endpoint}")
    response.raise_for_status()
    return response.json()

async def load_dashboard():
    async with httpx.AsyncClient(timeout=20) as client:
        users = fetch("users", client)
        posts = fetch("posts", client)
        comments = fetch("comments", client)
        albums = fetch("albums", client)
        todos = fetch("todos", client)
        (
            users_data,
            posts_data,
            comments_data,
            albums_data,
            todos_data
        ) = await asyncio.gather(
            users,
            posts,
            comments,
            albums,
            todos
        )
        return {
            "users": len(users_data),
            "posts": len(posts_data),
            "comments": len(comments_data),
            "albums": len(albums_data),
            "todos": len(todos_data)
        }

if __name__ == "__main__":
    dashboard = asyncio.run(load_dashboard())
    print(dashboard)

Instead of five sequential HTTP requests, every request begins immediately.

For dashboards and backend APIs, the difference is immediately noticeable.

5. Async Frameworks Make Much More Sense Once You Understand the Basics

I used to think frameworks like FastAPI were responsible for being fast.

They’re not.

They simply embrace asynchronous programming from the beginning.

Once you understand async functions, modern backend frameworks become much easier to reason about.

from fastapi import FastAPI
import asyncio
import random
app = FastAPI()
async def load_profile(user_id: int):
    await asyncio.sleep(random.uniform(0.3, 1.0))
    return {
        "id": user_id,
        "name": f"User {user_id}"
    }
async def load_notifications(user_id: int):
    await asyncio.sleep(random.uniform(0.2, 0.8))
    return [
        "Deployment completed",
        "Invoice generated",
        "Backup successful"
    ]
@app.get("/dashboard/{user_id}")
async def dashboard(user_id: int):
    profile, notifications = await asyncio.gather(
        load_profile(user_id),
        load_notifications(user_id)
    )
    return {
        "profile": profile,
        "notifications": notifications
    }

This pattern appears everywhere in modern backend development.

6. Async Doesn’t Replace Threads or Processes

For a while, I thought async was the “new” way to achieve concurrency.

It isn’t.

It’s simply another tool.

Each approach solves a different problem.

TechniqueBest ForAsyncI/O-bound workloadsThreadsBlocking libraries and mixed workloadsProcessesCPU-intensive computation

One lesson I learned the hard way is that choosing the wrong concurrency model often creates more problems than it solves.

The best backend systems combine these approaches instead of treating them as competitors.

Pro Tip: Use async to avoid waiting. Use processes to do heavy work. They’re complementary, not competing solutions.

7. Async Makes Streaming Feel Natural

Modern applications rarely send one large response anymore.

Instead, they stream information gradually.

AI assistants.

Live dashboards.

Real-time analytics.

Log viewers.

Chat applications.

Progress updates.

Async programming makes these workflows feel remarkably straightforward.

import asyncio
from datetime import datetime
async def stream_logs():
    for index in range(10):
        await asyncio.sleep(1)
        print(
            f"[{datetime.now()}] "
            f"Processing batch {index}"
        )
asyncio.run(stream_logs())

The same principles scale naturally to WebSockets, Server-Sent Events, and AI response streaming.

8. The Biggest Improvement Wasn’t Performance — It Was Scalability

People often ask me whether async made my applications “faster.”

Sometimes it did.

But that wasn’t the biggest benefit.

The real improvement appeared when traffic increased.

Instead of dedicating one worker to one waiting request, asynchronous applications allow each worker to serve many waiting clients efficiently.

That translates into:

  • Better resource utilization
  • Lower infrastructure costs
  • Higher request throughput
  • Improved responsiveness under load
  • More predictable latency

Those advantages become increasingly important as systems grow.

Final Thoughts

Learning Async Python took me longer than learning most Python features.

Not because the syntax was difficult.

Because the mental model was different.

Once I stopped thinking about execution in a straight line and started thinking about waiting, everything became clearer.

Today, nearly every backend project I build includes asynchronous programming somewhere in its architecture.

Not because it’s trendy.

Because modern applications spend much of their lives communicating with databases, APIs, cloud services, queues, and external systems.

Waiting is inevitable.

Wasting that waiting time isn’t.

That’s why I believe Async Python isn’t just another language feature anymore.

For modern backend development, it’s becoming an essential skill.


메타데이터
post_id
87f7d210bf02
slug
why-learning-async-python-completely-changed-how-i-build-modern-backend-systems-87f7d210bf02
url
https://medium.com/top-python-libraries/why-learning-async-python-completely-changed-how-i-build-modern-backend-systems-87f7d210bf02
canonical_url
https://medium.com/top-python-libraries/why-learning-async-python-completely-changed-how-i-build-modern-backend-systems-87f7d210bf02
author_url
https://medium.com/@maximilianoliver25
status
ok
fetched_at
2026-07-08 23:38:59