A Guide to Python Coroutines and asyncio for Beginners#
1. Understanding Asynchronous Programming through Real-Life Scenarios#
1.1 Two Ways to Buy Milk Tea#
Suppose you want to buy three cups of milk tea, each taking 2 minutes to make:
Traditional Method (Synchronous):
def buy_milk_tea_sync():
for _ in range(3):
wait_2_minutes() # Just waiting without doing anything
get_milk_tea()
# Total time: 3×2=6 minutes ❌
Smart Method (Asynchronous):
async def buy_milk_tea_async():
order_list = [place_order(), place_order(), place_order()] # Place orders simultaneously
await asyncio.gather(*order_list) # Wait while using the phone
# Total time: 2 minutes ✅
1.2 Coroutines are like Delivery Riders#
Imagine a delivery rider handling multiple orders at the same time:
- Picking up food from Store A (going to Store B while waiting)
- Receiving new orders on the way (flexibly adjusting the route)
- Immediately taking the next order after delivery (not wasting time)
This is how coroutines work! You don't need multiple riders (threads); one can efficiently complete the tasks.
2. The Simplest Introduction to Coroutines (with runnable code)#
2.1 Hello Coroutine Version#
import asyncio
async def greet(name): # Key 1: async defines a coroutine
print(f"{name} starts working")
await asyncio.sleep(1) # Key 2: suspend when encountering a wait
print(f"{name} has finished the task")
async def main_task():
await asyncio.gather(
greet("Xiao Ming"),
greet("Xiao Hong")
)
asyncio.run(main_task()) # Key 3: start the event loop
Output:
Xiao Ming starts working
Xiao Hong starts working
(waiting for 1 second)
Xiao Ming has finished the task
Xiao Hong has finished the task
2.2 Execution Process Diagram#
3. Three Core Concepts You Must Master#
3.1 Three Elements of Coroutines#
Element | Description | Analogy |
---|---|---|
async def | Declare a coroutine function | Labeling a delivery order as "urgent" |
await | Pause and yield control | The rider temporarily leaves to deliver other orders |
Event Loop | The scheduler coordinating all tasks | The order dispatch system of the delivery platform |
3.2 Common Misconceptions#
-
Error: Using await in a regular function
def regular_function(): await asyncio.sleep(1) # Error!
-
Error: Forgetting to create tasks
async def error_example(): # Sequential execution, no concurrency! await task1() await task2()
-
Correct Approach:
async def correct_example(): task1 = asyncio.create_task(task1()) task2 = asyncio.create_task(task2()) await task1 await task2
4. Hands-On Practice: Downloading Multiple Images#
4.1 Synchronous Version (Turtle Speed)#
import requests
def download_image(url):
print(f"Starting download {url}")
data = requests.get(url).content
with open("image.jpg", "wb") as f:
f.write(data)
print(f"Download complete {url}")
def main_function():
urls = ["url1", "url2", "url3"] # Assuming 3 image addresses
for url in urls:
download_image(url)
# Total time: time per image × quantity
4.2 Asynchronous Version (Feeling like flying)#
import aiohttp
async def async_download(url):
async with aiohttp.ClientSession() as session:
print(f"Starting download {url}")
async with session.get(url) as response:
data = await response.read()
with open(f"{url.split('/')[-1]}", "wb") as f:
f.write(data)
print(f"Download complete {url}")
async def main_task():
urls = ["url1", "url2", "url3"]
await asyncio.gather(*[async_download(url) for url in urls])
asyncio.run(main_task())
4.3 Performance Comparison#
Number of Images | Synchronous Time | Asynchronous Time | Speed Improvement |
---|---|---|---|
10 | 20s | 2s | 10x |
100 | 200s | 5s | 40x |
5. Frequently Asked Questions#
Q1: What is the difference between coroutines and multithreading?#
Feature | Coroutines | Multithreading |
---|---|---|
Resource Usage | One thread handles all | Each thread needs independent resources |
Switching Method | Actively yields control | Forced switching by the system |
Suitable Scenarios | Suitable for a lot of IO operations | Suitable for CPU-intensive tasks |
Programming Difficulty | Requires understanding of asynchronous syntax | Needs to handle thread safety issues |
Q2: When should coroutines not be used?#
- Scenarios requiring heavy CPU computation (e.g., video transcoding)
- Using libraries that do not support asynchronous operations (like traditional database drivers)
- Need for cross-core parallel computation (requires combining with multiprocessing)
Q3: How to debug coroutine programs?#
-
Use
asyncio.run()
as the entry point -
Use regular print statements inside coroutines
-
Use a professional debugger:
import logging logging.basicConfig(level=logging.DEBUG)
6. Recommended Learning Path#
6.1 Three Steps for Beginners#
- Write synchronous code first to understand the business process
- Replace time-consuming operations with async/await
- Use
asyncio.gather
to achieve concurrency
6.2 Recommended Practice Projects#
Project Type | Functionality | Skill Points |
---|---|---|
Weather Query | Query weather for multiple cities simultaneously | Basic asynchronous requests |
Website Monitoring | Regularly check the status of multiple websites | Asynchronous scheduled tasks |
Chatbot | Handle messages from multiple users simultaneously | Concurrent message processing |
7. Remember These 5 Sentences#
- async def: The starting line for declaring a coroutine
- await: Raise your hand to pause when encountering IO
- Event Loop: The behind-the-scenes scheduler
- create_task: Turn coroutines into executable tasks
- asyncio.run(): The program's startup switch
This article is synchronized and updated by Mix Space to xLog. The original link is https://blog.kanes.top/posts/default/asyncio