banner
kanes

kanes

A Guide to Python Coroutines and asyncio That Even Beginners Can Understand

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#

|700x615


3. Three Core Concepts You Must Master#

3.1 Three Elements of Coroutines#

ElementDescriptionAnalogy
async defDeclare a coroutine functionLabeling a delivery order as "urgent"
awaitPause and yield controlThe rider temporarily leaves to deliver other orders
Event LoopThe scheduler coordinating all tasksThe order dispatch system of the delivery platform

3.2 Common Misconceptions#

  1. Error: Using await in a regular function

    def regular_function():
        await asyncio.sleep(1)  # Error!
    
  2. Error: Forgetting to create tasks

    async def error_example():
        # Sequential execution, no concurrency!
        await task1()
        await task2()
    
  3. 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 ImagesSynchronous TimeAsynchronous TimeSpeed Improvement
1020s2s10x
100200s5s40x

5. Frequently Asked Questions#

Q1: What is the difference between coroutines and multithreading?#

FeatureCoroutinesMultithreading
Resource UsageOne thread handles allEach thread needs independent resources
Switching MethodActively yields controlForced switching by the system
Suitable ScenariosSuitable for a lot of IO operationsSuitable for CPU-intensive tasks
Programming DifficultyRequires understanding of asynchronous syntaxNeeds 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?#

  1. Use asyncio.run() as the entry point

  2. Use regular print statements inside coroutines

  3. Use a professional debugger:

    import logging
    logging.basicConfig(level=logging.DEBUG)
    

6.1 Three Steps for Beginners#

  1. Write synchronous code first to understand the business process
  2. Replace time-consuming operations with async/await
  3. Use asyncio.gather to achieve concurrency
Project TypeFunctionalitySkill Points
Weather QueryQuery weather for multiple cities simultaneouslyBasic asynchronous requests
Website MonitoringRegularly check the status of multiple websitesAsynchronous scheduled tasks
ChatbotHandle messages from multiple users simultaneouslyConcurrent message processing

7. Remember These 5 Sentences#

  1. async def: The starting line for declaring a coroutine
  2. await: Raise your hand to pause when encountering IO
  3. Event Loop: The behind-the-scenes scheduler
  4. create_task: Turn coroutines into executable tasks
  5. 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

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.