- What is async/await β writing code that can run multiple things at once
- Sync vs Async β understanding the difference
- How to use async/await β the basic syntax
- Running async code β using asyncio
- Multiple tasks β running many tasks together
- Real-world use β web requests and more
What is Async/Await?
Async/await is a way to write code that can do multiple things at the same time without waiting for each thing to finish before starting the next.
Think of it like cooking dinner. Instead of chopping all the vegetables, then boiling the water, then cooking the pasta one after another (synchronous), you can start the water boiling, while that's happening, chop the vegetables, while that's happening, start cooking the sauce (asynchronous).
In Python, async and await help you write this kind of code. They let you pause a function and let other functions run while you wait.
π‘ Key concept: Async code doesn't run multiple things at the exact same time. It runs one thing, then pauses and runs another, switching back and forth.
Sync vs Async
Understanding the Difference
Let's see the difference between synchronous and asynchronous code with a simple example.
# Sync vs Async Code
import time
import asyncio
print("=" * 50)
print("SYNC vs ASYNC CODE")
print("=" * 50)
# ============================================================
# SYNCHRONOUS CODE (One at a time)
# ============================================================
print("\n1. SYNCHRONOUS CODE")
def sync_task(name, delay):
"""Simulate a task that takes time"""
print(f" Starting {name}")
time.sleep(delay) # Blocking β nothing else can happen
print(f" Finished {name}")
return f"{name} done"
def sync_main():
"""Run tasks one at a time"""
print(" Running synchronous tasks...")
# Each task waits for the previous one to finish
result1 = sync_task("Task 1", 2)
result2 = sync_task("Task 2", 2)
result3 = sync_task("Task 3", 2)
print(f" All done! Results: {result1}, {result2}, {result3}")
start = time.time()
sync_main()
print(f" Total time: {time.time() - start:.2f} seconds")
# ============================================================
# ASYNCHRONOUS CODE (Switch between tasks)
# ============================================================
print("\n2. ASYNCHRONOUS CODE")
async def async_task(name, delay):
"""Simulate a task that takes time (non-blocking)"""
print(f" Starting {name}")
await asyncio.sleep(delay) # Non-blocking β other tasks can run
print(f" Finished {name}")
return f"{name} done"
async def async_main():
"""Run tasks concurrently"""
print(" Running asynchronous tasks...")
# Start all tasks at once
task1 = async_task("Task 1", 2)
task2 = async_task("Task 2", 2)
task3 = async_task("Task 3", 2)
# Wait for all to complete
results = await asyncio.gather(task1, task2, task3)
print(f" All done! Results: {', '.join(results)}")
# Run the async code
start = time.time()
asyncio.run(async_main())
print(f" Total time: {time.time() - start:.2f} seconds")
# ============================================================
# THE DIFFERENCE
# ============================================================
print("\n" + "-" * 30)
print("THE DIFFERENCE")
print("-" * 30)
print("""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SYNCHRONOUS ASYNCHRONOUS β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Runs one thing at a time Can switch between tasks β
β Waits for each task to Starts tasks, then waits β
β complete before starting for all to complete β
β the next together β
β β
β Total time: 6 seconds Total time: 2 seconds β
β (3 tasks Γ 2 seconds) (all tasks run together) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
Async code can save time when tasks are waiting for
external things (network requests, file I/O, etc.)
""")
Sync vs async key points:
- Synchronous β runs one thing at a time, waits for each to finish
- Asynchronous β starts tasks, switches between them while waiting
- Better with I/O β async helps with network, file operations
- Not always faster β async adds overhead for simple tasks
Quick Check: What's the main difference between sync and async code? (Answer: Sync runs one at a time; async can switch between tasks while waiting)
Using async and await
The Basic Syntax
Using async/await is simple. You just need to know two keywords:
async defβ defines a function that can be pausedawaitβ pauses the function until something is ready
# async and await Basics
import asyncio
print("=" * 50)
print("ASYNC AND AWAIT BASICS")
print("=" * 50)
# ============================================================
# CREATING AN ASYNC FUNCTION
# ============================================================
print("\n1. CREATING ASYNC FUNCTIONS")
async def simple_async():
"""A simple async function"""
print(" Starting async function")
await asyncio.sleep(1) # Wait for 1 second
print(" Finished async function")
return "Done!"
# This doesn't run the function β it creates a coroutine
result = simple_async()
print(f" Type: {type(result)}")
print(f" Result object: {result}")
# ============================================================
# AWAITING A SINGLE TASK
# ============================================================
print("\n2. AWAITING A SINGLE TASK")
async def wait_one_second():
"""Wait for one second"""
print(" Waiting...")
await asyncio.sleep(1)
print(" Done waiting")
return "Waited 1 second"
async def run_single():
result = await wait_one_second()
print(f" Result: {result}")
# asyncio.run(run_single())
# ============================================================
# FUNCTIONS THAT DON'T RETURN ANYTHING
# ============================================================
print("\n3. FUNCTIONS THAT RETURN NOTHING")
async def log_message(message):
"""Async function that returns nothing"""
await asyncio.sleep(0.5)
print(f" Log: {message}")
async def run_log():
await log_message("Hello from async!")
await log_message("This is another message")
# asyncio.run(run_log())
# ============================================================
# ASYNC FUNCTIONS WITH PARAMETERS
# ============================================================
print("\n4. ASYNC FUNCTIONS WITH PARAMETERS")
async def greet(name, delay):
"""Greet someone after a delay"""
await asyncio.sleep(delay)
return f"Hello, {name}! (after {delay}s)"
async def run_greeting():
result = await greet("Alice", 1)
print(f" Result: {result}")
result2 = await greet("Bob", 0.5)
print(f" Result: {result2}")
# asyncio.run(run_greeting())
# ============================================================
# RULES TO REMEMBER
# ============================================================
print("\n" + "-" * 30)
print("RULES FOR ASYNC/AWAIT")
print("-" * 30)
print("""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β RULES β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 1. You can only use await inside async functions β
β β
β 2. An async function always returns a coroutine object β
β β
β 3. To run async code, you need to use asyncio.run() β
β β
β 4. Await pauses the function, but doesn't block other functions β
β β
β 5. Only use await on awaitable things (async functions, tasks) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""")
async/await syntax key points:
- async def β creates an async function (coroutine)
- await β pauses and waits for something to finish
- Only inside async β you can only use
awaitin async functions - Returns coroutine β async functions return coroutine objects
- Need runner β use
asyncio.run()to run async code
Quick Check: Can you use await outside of an async function? (Answer: No β await can only be used inside async functions)
How to Run Async Code
Using asyncio.run()
To run async code, you need something called an event loop. The easiest way is to use asyncio.run().
Think of the event loop like a manager that decides which task runs next. It keeps switching between tasks that are waiting, making sure everything gets done.
# How to Run Async Code
import asyncio
import time
print("=" * 50)
print("RUNNING ASYNC CODE")
print("=" * 50)
# ============================================================
# METHOD 1: asyncio.run() (The simple way)
# ============================================================
print("\n1. asyncio.run()")
async def hello_world():
"""A simple async function"""
print(" Hello!")
await asyncio.sleep(0.5)
print(" World!")
# This is the easiest way to run async code
# asyncio.run(hello_world())
print(" β
Use asyncio.run() for simple async code")
# ============================================================
# METHOD 2: Creating tasks and running them
# ============================================================
print("\n2. CREATING TASKS")
async def task_one():
await asyncio.sleep(1)
return "Task 1 done"
async def task_two():
await asyncio.sleep(2)
return "Task 2 done"
async def run_tasks():
# Create tasks (start them)
t1 = asyncio.create_task(task_one())
t2 = asyncio.create_task(task_two())
# Wait for them to finish
result1 = await t1
result2 = await t2
return result1, result2
# results = asyncio.run(run_tasks())
# print(f" Results: {results}")
# ============================================================
# METHOD 3: Running in Jupyter/Interactive
# ============================================================
print("\n3. RUNNING IN JUPYTER NOTEBOOK")
# In Jupyter, you can use:
# await hello_world()
print(" β
In Jupyter, you can use await directly")
print(" β In regular Python, you need asyncio.run()")
# ============================================================
# COMPARISON: RUNNING SYNC CODE FROM ASYNC
# ============================================================
print("\n4. RUNNING SYNC CODE FROM ASYNC")
import asyncio
def sync_function():
"""A regular (blocking) function"""
print(" Running sync function...")
time.sleep(1) # This blocks everything!
print(" Sync function done")
return "Sync result"
async def run_with_sync():
print(" Async: Before sync call")
# This will block β not good in async code
result = sync_function()
print(f" Async: After sync call: {result}")
return result
# asyncio.run(run_with_sync())
# ============================================================
# RUNNING BLOCKING CODE WITH run_in_executor
# ============================================================
print("\n5. RUNNING BLOCKING CODE (BETTER WAY)")
async def run_sync_properly():
"""Run blocking code without blocking the event loop"""
print(" Async: Before sync call")
# Run blocking code in a separate thread
loop = asyncio.get_running_loop()
result = await loop.run_in_executor(None, sync_function)
print(f" Async: After sync call: {result}")
return result
print(" β
Use run_in_executor for blocking code")
print(" This prevents blocking the event loop")
# ============================================================
# SUMMARY
# ============================================================
print("\n" + "-" * 30)
print("SUMMARY β RUNNING ASYNC CODE")
print("-" * 30)
print("""
βββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββ
β METHOD β BEST USE CASE β
βββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββ€
β asyncio.run() β Simple programs, scripts β
β β β
β create_task() β Running multiple tasks together β
β β β
β await directly (Jupyter) β Interactive environments β
β β β
β run_in_executor() β Running blocking code in async code β
βββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββββ
π asyncio.run() is the simplest way to run async code
""")
Running async code key points:
- asyncio.run() β the simplest way to run async code
- create_task() β run multiple tasks concurrently
- Event loop β the engine that manages async tasks
- run_in_executor β run blocking code without blocking
Quick Check: What function do you use to run async code in a regular Python script? (Answer: asyncio.run())
Running Multiple Tasks
Running Many Things at Once
The real power of async is running multiple tasks at the same time. Here are the different ways to do it.
# Running Multiple Tasks
import asyncio
import time
print("=" * 50)
print("RUNNING MULTIPLE TASKS")
print("=" * 50)
# ============================================================
# asyncio.gather() β Run multiple tasks
# ============================================================
print("\n1. asyncio.gather()")
async def fetch_data(endpoint, delay):
"""Simulate fetching data from an API"""
print(f" Fetching from {endpoint}...")
await asyncio.sleep(delay)
print(f" Done fetching from {endpoint}")
return f"Data from {endpoint}"
async def gather_example():
# Run all tasks at once and wait for all to finish
results = await asyncio.gather(
fetch_data("users", 2),
fetch_data("posts", 1.5),
fetch_data("comments", 1)
)
return results
# results = asyncio.run(gather_example())
# print(f" Results: {results}")
# ============================================================
# asyncio.wait() β More control
# ============================================================
print("\n2. asyncio.wait()")
async def wait_example():
tasks = [
asyncio.create_task(fetch_data("users", 2)),
asyncio.create_task(fetch_data("posts", 1.5)),
asyncio.create_task(fetch_data("comments", 1))
]
# Wait for all tasks to complete
done, pending = await asyncio.wait(tasks)
results = []
for task in done:
results.append(task.result())
return results
# results = asyncio.run(wait_example())
# print(f" Results: {results}")
# ============================================================
# asyncio.gather() vs asyncio.wait()
# ============================================================
print("\n3. COMPARISON")
print("""
βββββββββββββββββββββββ¬βββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββ
β FEATURE β asyncio.gather() β asyncio.wait() β
βββββββββββββββββββββββΌβββββββββββββββββββββββββββΌβββββββββββββββββββββββββββ€
β Returns β List of results β (done, pending) tuples β
β β β β
β Error handling β If one fails, all raise β Can handle individually β
β β β β
β Use case β Simple "run all" cases β More control needed β
βββββββββββββββββββββββ΄βββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββ
""")
# ============================================================
# COMPARE SYNC VS ASYNC PERFORMANCE
# ============================================================
print("\n4. COMPARING PERFORMANCE")
async def async_demo():
print(" Running async tasks...")
start = time.time()
await asyncio.gather(
asyncio.sleep(2),
asyncio.sleep(2),
asyncio.sleep(2)
)
print(f" Async time: {time.time() - start:.2f}s")
def sync_demo():
print(" Running sync tasks...")
start = time.time()
time.sleep(2)
time.sleep(2)
time.sleep(2)
print(f" Sync time: {time.time() - start:.2f}s")
print(" β‘ Async: 3 tasks of 2 seconds = 2 seconds total")
print(" π’ Sync: 3 tasks of 2 seconds = 6 seconds total")
# ============================================================
# ASYNC WITH DIFFERENT DELAYS
# ============================================================
print("\n5. ASYNC WITH DIFFERENT DELAYS")
async def delayed_task(name, delay):
"""A task with a custom delay"""
print(f" Task {name}: starting (will take {delay}s)")
await asyncio.sleep(delay)
print(f" Task {name}: finished")
return f"Task {name} done in {delay}s"
async def run_mixed():
# These tasks have different delays
results = await asyncio.gather(
delayed_task("A", 3),
delayed_task("B", 1),
delayed_task("C", 2)
)
print(f" All tasks completed in the order they finished!")
for result in results:
print(f" {result}")
# asyncio.run(run_mixed())
# ============================================================
# HANDLING ERRORS IN GATHER
# ============================================================
print("\n6. HANDLING ERRORS")
async def failing_task(name, fail):
"""A task that might fail"""
await asyncio.sleep(0.5)
if fail:
raise ValueError(f"Task {name} failed!")
return f"Task {name} succeeded!"
async def run_with_errors():
try:
# This will raise if any task fails
results = await asyncio.gather(
failing_task("A", False),
failing_task("B", True), # This one fails
failing_task("C", False)
)
except ValueError as e:
print(f" Error caught: {e}")
else:
print(f" Results: {results}")
print(" β
gather() raises an exception if any task fails")
# ============================================================
# RETURN_EXCEPTIONS
# ============================================================
print("\n7. RETURN_EXCEPTIONS β Handle failures gracefully")
async def run_with_return_exceptions():
# Even if tasks fail, return the exceptions as results
results = await asyncio.gather(
failing_task("A", False),
failing_task("B", True),
failing_task("C", False),
return_exceptions=True
)
print(" Results (with exceptions):")
for result in results:
if isinstance(result, Exception):
print(f" {result}")
else:
print(f" {result}")
print(" β
return_exceptions=True lets you handle failures individually")
# asyncio.run(run_with_return_exceptions())
Multiple tasks key points:
- gather() β runs multiple tasks and returns all results
- wait() β gives more control over task completion
- create_task() β starts a task without waiting
- return_exceptions β handles failures gracefully
Quick Check: What function runs multiple async tasks and waits for all to finish? (Answer: asyncio.gather())
Real-World Example
Fetching Data from Multiple APIs
# Real-World Example: Fetching Data from APIs
import asyncio
import time
import random
print("=" * 60)
print("FETCHING DATA FROM MULTIPLE APIs")
print("=" * 60)
# ============================================================
# SIMULATED API CALLS
# ============================================================
async def fetch_api(name, delay, success_rate=0.9):
"""Simulate fetching data from an API"""
print(f" π Calling {name} API...")
# Simulate network delay
await asyncio.sleep(delay)
# Simulate occasional failure
if random.random() > success_rate:
raise Exception(f"{name} API failed!")
print(f" β
{name} API responded")
return {
"api": name,
"data": f"Data from {name}",
"delay": delay
}
# ============================================================
# FETCH MULTIPLE APIS
# ============================================================
async def fetch_all_apis():
"""Fetch data from multiple APIs concurrently"""
print("\n Starting API calls...")
apis = [
fetch_api("Users", 1.5, 0.95),
fetch_api("Posts", 2.0, 0.9),
fetch_api("Comments", 1.0, 0.85),
fetch_api("Profiles", 0.8, 0.95)
]
# Run all API calls together
start = time.time()
results = await asyncio.gather(*apis, return_exceptions=True)
elapsed = time.time() - start
print(f"\n All API calls completed in {elapsed:.2f}s")
# Process results
success_count = 0
for result in results:
if isinstance(result, Exception):
print(f" β {result}")
else:
print(f" β
{result['api']}: {result['data']} (took {result['delay']}s)")
success_count += 1
print(f"\n Summary: {success_count}/{len(apis)} APIs succeeded")
# ============================================================
# FETCH WITH TIMEOUT
# ============================================================
async def fetch_with_timeout(api_name, delay, timeout):
"""Fetch data with a timeout"""
try:
result = await asyncio.wait_for(
fetch_api(api_name, delay),
timeout=timeout
)
return result
except asyncio.TimeoutError:
return f"β {api_name} timed out after {timeout}s"
async def fetch_with_timeouts():
"""Fetch data with different timeouts"""
print("\n Fetching with timeouts...")
results = await asyncio.gather(
fetch_with_timeout("Fast API", 0.5, 1.0),
fetch_with_timeout("Slow API", 2.0, 1.0),
fetch_with_timeout("Medium API", 1.0, 1.0),
return_exceptions=True
)
for result in results:
print(f" {result}")
# ============================================================
# PROCESS DATA AS IT ARRIVES
# ============================================================
async def process_as_it_arrives():
"""Process data as soon as each API responds"""
print("\n Processing data as it arrives...")
apis = [
fetch_api("API 1", 2.0),
fetch_api("API 2", 1.0),
fetch_api("API 3", 1.5),
fetch_api("API 4", 0.5)
]
# Create tasks
tasks = [asyncio.create_task(api) for api in apis]
# Process as they complete
for task in asyncio.as_completed(tasks):
try:
result = await task
print(f" π Processed: {result['api']} (took {result['delay']}s)")
except Exception as e:
print(f" β Error: {e}")
# ============================================================
# DEMONSTRATION
# ============================================================
print("\n1. FETCHING ALL APIS")
asyncio.run(fetch_all_apis())
print("\n2. FETCHING WITH TIMEOUTS")
asyncio.run(fetch_with_timeouts())
print("\n3. PROCESSING AS IT ARRIVES")
asyncio.run(process_as_it_arrives())
# ============================================================
# KEY TAKEAWAYS
# ============================================================
print("\n" + "=" * 60)
print("KEY TAKEAWAYS")
print("=" * 60)
print("""
β
Async/await is great for I/O-bound operations
β
API calls, database queries, file operations
β
Multiple requests can be done concurrently
β
Use gather() for multiple tasks
β
Use wait_for() for timeouts
β
Process results as they arrive with as_completed()
β
Async saves time β 4 APIs at 2s each = 2s total vs 8s sync
""")
Real-world example key points:
- API calls β perfect for async because they wait for network
- gather() β runs multiple API calls together
- Timeout β use
wait_for()to prevent hanging - as_completed() β process results as they arrive
- Massive speedup β 4 APIs at 2s each = 2s async vs 8s sync
Quick Check: When is async/await most useful? (Answer: When doing I/O operations like API calls, database queries, and file operations)
Best Practices
Using Async/Await Effectively
# Best Practices for Async/Await
import asyncio
import time
print("=" * 60)
print("BEST PRACTICES FOR ASYNC/AWAIT")
print("=" * 60)
# ============================================================
# 1. USE ASYNC ONLY FOR I/O OPERATIONS
# ============================================================
print("\n1. USE ASYNC ONLY FOR I/O OPERATIONS")
# β BAD: Using async for CPU-bound work
async def bad_async():
# This does heavy computation β async won't help!
total = 0
for i in range(1000000):
total += i
return total
# β
GOOD: Use async for I/O operations
async def good_async():
# This waits for external things
await asyncio.sleep(0.1)
return "API response"
print(" β
Use async for I/O: network, files, databases")
print(" β Don't use async for CPU: math, loops, calculations")
# ============================================================
# 2. DON'T MIX ASYNC AND SYNC BLOCKING CODE
# ============================================================
print("\n2. DON'T MIX ASYNC AND SYNC BLOCKING CODE")
# β BAD: Blocking code in async function
async def bad_mix():
print(" Async: before blocking")
time.sleep(1) # This blocks the whole event loop!
print(" Async: after blocking")
# β
GOOD: Use run_in_executor for blocking code
async def good_mix():
print(" Async: before blocking")
loop = asyncio.get_running_loop()
result = await loop.run_in_executor(None, time.sleep, 1)
print(" Async: after blocking")
print(" β Don't use time.sleep() in async functions")
print(" β
Use asyncio.sleep() or run_in_executor")
# ============================================================
# 3. USE ASYNCIO.GATHER FOR MULTIPLE TASKS
# ============================================================
print("\n3. USE ASYNCIO.GATHER FOR MULTIPLE TASKS")
# β BAD: Awaiting tasks one by one
async def bad_gather():
result1 = await asyncio.sleep(1)
result2 = await asyncio.sleep(1)
result3 = await asyncio.sleep(1)
return "Done"
# β
GOOD: Using gather for concurrent execution
async def good_gather():
results = await asyncio.gather(
asyncio.sleep(1),
asyncio.sleep(1),
asyncio.sleep(1)
)
return "Done"
print(" β
Use gather() for concurrent tasks")
print(" β Don't await tasks one by one (it's sequential)")
# ============================================================
# 4. SET TIMEOUTS
# ============================================================
print("\n4. SET TIMEOUTS")
async def slow_task():
await asyncio.sleep(10)
return "Done"
async def with_timeout():
try:
result = await asyncio.wait_for(slow_task(), timeout=2)
print(f" Result: {result}")
except asyncio.TimeoutError:
print(" β° Task timed out!")
print(" β
Always set timeouts for external calls")
# ============================================================
# 5. HANDLE EXCEPTIONS
# ============================================================
print("\n5. HANDLE EXCEPTIONS")
async def might_fail():
await asyncio.sleep(0.5)
raise ValueError("Something went wrong!")
async def with_error_handling():
try:
result = await might_fail()
print(f" Result: {result}")
except ValueError as e:
print(f" β Caught error: {e}")
print(" β
Always handle exceptions in async code")
# ============================================================
# 6. USE RETURN_EXCEPTIONS IN GATHER
# ============================================================
print("\n6. USE RETURN_EXCEPTIONS")
async def with_return_exceptions():
results = await asyncio.gather(
asyncio.sleep(0.1),
might_fail(),
asyncio.sleep(0.1),
return_exceptions=True
)
for result in results:
if isinstance(result, Exception):
print(f" β {result}")
else:
print(f" β
{result}")
print(" β
Use return_exceptions to handle failures gracefully")
# ============================================================
# 7. SUMMARY
# ============================================================
print("\n" + "=" * 60)
print("BEST PRACTICES SUMMARY")
print("=" * 60)
print("""
βββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββ
β PRACTICE β WHY IT MATTERS β
βββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββ€
β Use async for I/O only β Async doesn't help CPU-bound work β
β β β
β Don't block the event loop β Blocking code defeats async performance β
β β β
β Use gather() for concurrencyβ Run multiple tasks together β
β β β
β Set timeouts β Prevent hanging on slow operations β
β β β
β Handle exceptions β Don't let errors crash everything β
β β β
β Use return_exceptions β Handle failures individually β
βββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββββ
π REMEMBER:
β’ Async is for I/O, not CPU
β’ Don't block the event loop
β’ Always set timeouts
β’ Handle errors gracefully
""")
Best practices summary:
- Use async for I/O β not for CPU-bound work
- Don't block the event loop β use
asyncio.sleep()nottime.sleep() - Use gather() β for concurrent tasks
- Set timeouts β prevent hanging
- Handle exceptions β don't let errors crash everything
Quick Check: Should you use async for CPU-heavy operations? (Answer: No β async is for I/O operations)
Try It Yourself
Experiment with async/await in the editor below.
ASYNC/AWAIT - PRACTICE
==================================================
1. BASIC ASYNC FUNCTION
2. RUNNING MULTIPLE TASKS
3. TIMEOUTS
4. COMPARE SYNC VS ASYNC
Running sync (one at a time):
Sync time: 1.00s
Running async (together):
Async time: 0.50s
You've Got It!
You now understand async/await in Python. You know how to write async functions, run multiple tasks together, and handle errors and timeouts.
Quick Quiz
Test what you've learned:
Frequently Asked Questions
What is async/await in Python?
Does async make code run faster?
Can I use await outside an async function?
await inside functions defined with async def. If you try to use it elsewhere, Python will give you a syntax error.
What's the difference between async and threads?
Is asyncio part of the standard library?
asyncio is part of Python's standard library. You don't need to install anything extra. Just import it with import asyncio.
Can I use async with Django or Flask?
Where to Go From Here
Now that you understand async/await in Python, check out these related topics:
Context Managers
Learn how context managers work with async code.
Learn More βGenerators
Learn about generators β another way to write async code.
Learn More βDecorators
Learn how to create async decorators.
Learn More β