Python24 min read
Python Async Await
Learn async and await with a clear mental model, understand concurrency vs parallelism, and write faster I/O programs like API callers and web scrapers.
David Miller
August 14, 2025
5.8k285
Async programming helps when your program spends time waiting, like:
- calling APIs
- reading files from disk
- talking to databases
- downloading images
Instead of waiting and doing nothing, async lets Python start another task while the first one is waiting.
## First, understand the idea (very important)
### Synchronous (normal code)
One task runs at a time. If task A is waiting, everything waits.
### Asynchronous (async code)
Task A can pause (await) and Python can run task B during that pause.
## Concurrency vs Parallelism
- **Concurrency**: tasks take turns (great for I/O waiting)
- **Parallelism**: tasks truly run at the same time (great for CPU-heavy work)
Async is mainly for **concurrency** (I/O work).
## Your first async function
```python
import asyncio
async def greet(name):
print(f"Hello {name}!")
await asyncio.sleep(1) # pretend we are waiting for network
print(f"Goodbye {name}!")
asyncio.run(greet("Tom"))
```
Expected output:
```
Hello Tom!
(wait 1 second)
Goodbye Tom!
```
### Why do we need 'await'?
Because it tells Python: "I am waiting here. You can run other tasks."
## Running multiple tasks at once
```python
import asyncio
async def fetch_data(task_id):
print(f"Task {task_id}: start")
await asyncio.sleep(2)
print(f"Task {task_id}: end")
return f"data-{task_id}"
async def main():
results = await asyncio.gather(
fetch_data(1),
fetch_data(2),
fetch_data(3),
)
print(results)
asyncio.run(main())
```
Expected output (order may vary):
```
Task 1: start
Task 2: start
Task 3: start
(wait ~2 seconds total)
Task 1: end
Task 2: end
Task 3: end
['data-1', 'data-2', 'data-3']
```
Notice: total time is about 2 seconds, not 6 seconds. That is the power of async.
## Real-world example: async HTTP requests
For real async HTTP, we usually use `aiohttp`.
```python
import asyncio
import aiohttp
async def fetch_url(session, url):
async with session.get(url) as resp:
return await resp.text()
async def main():
async with aiohttp.ClientSession() as session:
html = await fetch_url(session, "https://example.com")
print(html[:120])
asyncio.run(main())
```
## Common beginner mistakes
### Mistake 1: forgetting await
```python
# wrong idea:
# result = fetch_data(1) # this returns a coroutine, not the final data
```
### Mistake 2: using blocking code inside async
```python
# Avoid time.sleep() inside async code
# Use: await asyncio.sleep()
```
## Graph: how async scheduling works
```mermaid
flowchart LR
A[Task 1 starts] --> B[await: waiting]
B --> C[Event loop runs Task 2]
C --> D[Task 2 await]
D --> E[Event loop runs Task 3]
E --> F[Task 3 await]
F --> G[Resume Task 1 when ready]
```
## Key points
- Use async for I/O-bound work
- await = pause here, let others run
- asyncio.gather runs tasks concurrently
- For CPU-heavy work use multiprocessing (not async)
#Python#Advanced#Async