协程(Coroutine)是Python异步编程的核心,但许多开发者对其底层原理和演进过程一知半解。本文将通过生成器进化史的视角,带您从基础到实战完整掌握协程开发,最后还会揭秘async/await背后的魔法。

一、理解生成器(Generator)

生成器是一种惰性计算的迭代器,用 yield 关键字定义。它不会一次性生成所有数据,而是按需生成。

1.1 生成器的本质

def simple_gen():
print("start")
yield 1
print("continue")
yield 2
gen=simple_gen()
print('=====>test')
print(next(gen))
print('=====>test')
print(next(gen))
# 执行结果
# =====>test
# start
# 1
# =====>test
# continue
# 2

生成器通过yield实现执行暂停,每次调用next()恢复执行直到遇到下一个yield。

1.2 生成器的双向通信

def interactive_gen():
response = yield "What's your name?"
yield f"Hello, {response}!"

gen = interactive_gen()
print(next(gen)) # 输出:What's your name?
print(gen.send("Alice")) # 输出:Hello, Alice!

通过.send()方法实现双向数据传递,建立协程的雏形

二、生成器进化成协程

2.1 yield from语法

def sub_gen():
yield 2
yield 3

def main_gen():
yield 1
yield from sub_gen()
yield 4

list(main_gen()) # 输出:[1, 2, 3, 4]

yield from实现生成器委托,为协程的任务嵌套奠定基础

2.2 异常处理机制

def error_gen():
try:
yield "normal"
except ValueError:
yield "error"

gen = error_gen()
print(next(gen)) # 输出:normal
print(gen.throw(ValueError)) # 输出:error

.throw()和.close()方法让生成器具备完整的异常处理能力

三、现代协程体系:async/await

3.1 事件循环原理

想象一个高效的快递调度员:

import asyncio
async def delivery(name, time):
print(f"{name}快递开始送出")
await asyncio.sleep(time) # 挂起,非阻塞,让出控制权
print(f"{name}快递已送达")

async def main():
# 创建三个并行任务
tasks = [
delivery("A", 2),
delivery("B", 1),
delivery("C", 3)
]
await asyncio.gather(*tasks)

asyncio.run(main())

输出顺序:
A快递开始送出
B快递开始送出
C快递开始送出
B快递已送达
A快递已送达
C快递已送达
关键点:
并发执行:A 和 B 几乎同时开始。
非阻塞:await asyncio.sleep 不会阻塞线程,而是让出控制权给事件循环。

四、实战:异步HTTP客户端

4.1 使用aiohttp

import aiohttp

async def fetch_url(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()

async def batch_fetch():
urls = [...] # 100个URL
tasks = [fetch_url(url) for url in urls]
return await asyncio.gather(*tasks)

对比同步版本速度提升20倍以上