Back 🌈 1️⃣ What is an Async Function? 02 Mar, 2026

An async function is a function that:

  • Can pause execution

  • Lets other code run meanwhile

  • Then resume from where it stopped

It is defined using:

async def my_function():
    ...

🧠 Key Rule

When you call an async function:

result = my_function()

👉 It does NOT execute immediately
👉 It returns a coroutine object

Execution only starts when you:

  • await it

  • or run it inside an event loop (asyncio.run())


🎭 Intuitive Analogy

👨‍🍳 Normal Function = Single Chef Kitchen

def cook():
    boil_water()
    cut_vegetables()

Chef blocks everything until done.


🍽 Async Function = Restaurant Order System

async def cook():
    await boil_water()
    cut_vegetables()

When water is boiling (I/O wait), chef serves another customer.

👉 That’s async.


🏗 2️⃣ What Actually Happens Internally?

When you write:

async def fetch_data():
    return "Data"

And call:

x = fetch_data()

Python:

  1. Creates coroutine object

  2. Does NOT execute body

  3. Waits for event loop

The coroutine object is like:

📦 A paused execution plan


🔵 3️⃣ Role of await

🔥 What is await?

await tells Python:

"Pause here until this async task finishes. Meanwhile, let others run."


Example

async def task():
    print("Start")
    await asyncio.sleep(2)
    print("End")

When execution reaches:

await asyncio.sleep(2)

What happens?

  1. Task pauses

  2. Control goes back to event loop

  3. Event loop runs other tasks

  4. After 2 sec → task resumes


🚨 Important Rule

You can ONLY use await:

  • Inside async functions

  • On awaitable objects (coroutine, Task, Future)

This is invalid:

def normal():
    await something()  ❌

🟢 4️⃣ Role of asyncio.run()

Now big question:

If async function doesn’t run automatically…

Who runs it?

👉 The Event Loop


💡 What is Event Loop?

Event loop is:

The brain that manages and schedules all async tasks.

It:

  • Picks a task

  • Runs until it hits await

  • Switches to another task

  • Comes back later


🔥 What does asyncio.run() do?

asyncio.run(main())

It:

  1. Creates an event loop

  2. Schedules coroutine

  3. Runs until complete

  4. Closes loop

So it’s the entry point of async programs.


🔄 Execution Flow (Step-by-Step)

Let’s analyze this:

import asyncio

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

asyncio.run(greet())

Step-by-step:

  1. greet() → coroutine object created

  2. asyncio.run() starts event loop

  3. Event loop starts executing greet

  4. Prints "Hello"

  5. Hits await

  6. Pauses task

  7. Event loop waits 2 sec (or runs others)

  8. Resumes task

  9. Prints "World"

  10. Loop closes


🎨 Visual Timeline

Time →
Task A:  Start ---- Pause ------ Resume ---- Done
Task B:        Start --- Done

Instead of blocking like:

Task A: Start ------------ Done
Task B:              Start ----- Done

Async makes concurrency possible.


🆚 Async vs Normal Function (Deep Comparison)

FeatureNormal FunctionAsync Function
ExecutionImmediateDelayed
ReturnsValueCoroutine object
Can pause
Needs event loop
Good for CPU tasks
Good for I/O tasks

🚀 Real FastAPI Example (Important for You)

@app.get("/users")
async def get_users():
    users = await db.fetch_all()
    return users

Here:

  1. Request comes

  2. FastAPI calls async function

  3. DB query happens

  4. While waiting → server handles other users

  5. When DB returns → function resumes

This is why FastAPI handles 10k+ concurrent users efficiently.


🔴 Common Mistakes

❌ 1. Forgetting await

data = fetch_data()   # WRONG

You get coroutine object instead of result.


❌ 2. Using time.sleep()

time.sleep(5)

This blocks event loop ❌

Correct:

await asyncio.sleep(5)

🧬 Under the Hood (Advanced Understanding)

Async in Python uses:

  • Generators

  • Yield mechanics

  • Event-driven architecture

When you write:

await something()

Internally it's similar to:

yield from something()

Coroutine saves state and returns control to event loop.

That’s why it can resume exactly where it left.


🧠 Very Important Concept

Async ≠ Parallelism
Async = Concurrency

It does NOT use multiple CPU cores automatically.

It works best for:

  • API calls

  • Database queries

  • File operations

  • Network operations

It is NOT good for:

  • Heavy ML training

  • Image processing

  • CPU heavy loops

For those → use multiprocessing.


🎯 Deep Concept: Awaitable Objects

You can await:

  1. Coroutine

  2. Task

  3. Future

Example:

task = asyncio.create_task(greet())
await task

💎 Why This Matters for You

Since you're:

  • Learning FastAPI

  • Planning backend architecture

  • Working with PostgreSQL

  • Using N8N

  • Building AI systems

Async will control:

  • DB efficiency

  • API performance

  • Scalability

  • System throughput

If you master this, you become backend architect level.


🧠 Mental Model To Remember Forever

Think of async system as:

📞 Call center with 1 agent but smart call holding system.

Normal function:
Agent talks to 1 customer until call ends.

Async:
Agent puts customer on hold while checking info, talks to another, then comes back.


⚡ Final Summary

Async Function

  • Defined with async def

  • Returns coroutine object

  • Can pause execution

await

  • Pauses execution

  • Gives control back to event loop

  • Must be inside async function

asyncio.run()

  • Starts event loop

  • Runs coroutine

  • Entry point of async program

Event Loop

  • Manages all async tasks

  • Handles scheduling

  • Enables concurrency