Python协程函数
1. 协程函数的定义
在 Python 中,协程函数通过
async def 语法定义,它是一种特殊的函数类型,与普通函数不同的是:- 调用协程函数不会立即执行其内部代码,而是返回一个协程对象
- 协程函数内部可以使用
await关键字暂停执行,等待其他协程完成
# 定义一个简单的协程函数
async def fetch_data(url):
# 模拟网络请求
await asyncio.sleep(1)
return {"data": "example", "url": url}
2. 协程函数的调用与执行
协程函数的调用分为三个核心步骤:
- 创建协程对象:调用协程函数得到协程对象
- 调度协程执行:将协程对象提交给事件循环
- 等待结果返回:使用
await或asyncio.run()获取结果
import asyncio
async def fetch_data(url):
await asyncio.sleep(1)
return {"data": "example", "url": url}
# 错误调用方式(仅创建协程对象,不执行)
coro = fetch_data("https://example.com") # 不会执行协程内部代码
# 正确调用方式1:在另一个协程中使用 await
async def main():
result = await fetch_data("https://example.com")
print(result)
# 正确调用方式2:使用 asyncio.run() 运行顶层协程
asyncio.run(fetch_data("https://example.com"))
3. 协程函数的核心机制
3.1 await 关键字
await 是协程的核心机制,它的作用是:- 暂停当前协程的执行
- 将控制权交回事件循环
- 等待目标协程完成并返回结果
- 恢复当前协程的执行
async def task1():
print("Task 1 started")
await asyncio.sleep(2) # 暂停执行2秒
print("Task 1 finished")
async def task2():
print("Task 2 started")
await asyncio.sleep(1) # 暂停执行1秒
print("Task 2 finished")
async def main():
await task1() # 顺序执行:等待task1完成后才执行task2
await task2()
3.2 并发执行协程
使用
asyncio.gather() 可以并发执行多个协程:async def main():
# 并发执行两个协程
results = await asyncio.gather(
fetch_data("https://url1.com"),
fetch_data("https://url2.com")
)
print(results) # 同时获取两个协程的结果
3.3 创建后台任务
使用
asyncio.create_task() 创建可独立运行的任务:async def background_task():
await asyncio.sleep(3)
print("Background task completed")
async def main():
# 创建后台任务并立即执行
task = asyncio.create_task(background_task())
print("Main function continues...")
await task # 等待后台任务完成
4. 协程的生命周期管理
async def long_running_task():
try:
print("Task started")
await asyncio.sleep(10)
print("Task completed")
except asyncio.CancelledError:
print("Task cancelled")
async def main():
task = asyncio.create_task(long_running_task())
await asyncio.sleep(2)
# 取消任务
task.cancel()
try:
await task # 等待任务结束(可能抛出 CancelledError)
except asyncio.CancelledError:
print("Task was cancelled")
5. 协程的使用场景
5.1 I/O 密集型应用
- 网络爬虫:并发请求多个 URL
- API 调用:同时调用多个微服务
- 数据库操作:并发执行多个查询
async def fetch_urls(urls):
async with aiohttp.ClientSession() as session: # 使用 aiohttp 库
tasks = [fetch(session, url) for url in urls]
return await asyncio.gather(*tasks)
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
5.2 实时数据处理
- WebSocket 服务器:同时处理多个客户端连接
- 消息队列消费者:并发处理多个消息
import websockets
async def handler(websocket):
async for message in websocket:
await process_message(message)
async def main():
async with websockets.serve(handler, "localhost", 8765):
await asyncio.Future() # 保持服务器运行
5.3 异步任务编排
- 定时任务:使用
asyncio.sleep()实现异步定时器 - 任务流水线:一个任务的输出作为另一个任务的输入
async def producer(queue):
for i in range(5):
await queue.put(i)
await asyncio.sleep(1)
async def consumer(queue):
while True:
item = await queue.get()
print(f"Processing: {item}")
queue.task_done()
6. 协程与多线程 / 多进程的对比
| 特性 | 协程 | 多线程 | 多进程 |
|---|---|---|---|
| 并发方式 | 单线程,协作式调度 | 内核级线程调度 | 多个进程 |
| 创建成本 | 极低(微秒级) | 中等(毫秒级) | 高(毫秒级) |
| 切换成本 | 极低(纳秒级) | 较高(微秒级) | 高(毫秒级) |
| CPU 利用率 | 适合 I/O 密集型 | 适合 I/O 密集型 | 适合 CPU 密集型 |
| 共享资源 | 共享全局变量 | 共享全局变量 | 不共享 |
| 复杂度 | 中等(需理解异步) | 高(锁管理) | 高(进程间通信) |
7. 最佳实践与注意事项
- 避免阻塞事件循环:在协程中避免执行耗时的同步操作,否则会阻塞所有协程
# 错误做法:在协程中执行耗时同步操作
async def bad_example():
time.sleep(5) # 阻塞整个事件循环
# 正确做法:使用异步版本或运行在单独线程
async def good_example():
await asyncio.sleep(5) # 正确的异步睡眠
- 异常处理:协程中的未捕获异常可能导致整个应用崩溃
async def task():
raise ValueError("Oops!")
async def main():
try:
await task()
except ValueError as e:
print(f"Caught error: {e}")
- 资源管理:使用
async with和async for管理异步资源
async def process_file():
async with aiofiles.open("data.txt", "r") as f: # 使用 aiofiles 库
async for line in f:
await process_line(line)
8. 相关库与工具
- asyncio:Python 标准库,提供协程、事件循环、任务管理等核心功能
- aiohttp:异步 HTTP 客户端 / 服务器库,用于网络请求
- aioredis:异步 Redis 客户端,用于缓存和消息队列
- aiofiles:异步文件操作库,用于文件 I/O
- websockets:异步 WebSocket 库,用于实时通信
通过掌握协程函数的定义、调用和应用场景,你可以构建高性能、高并发的 Python 应用程序,尤其适合处理大
郭慕荣博客园

浙公网安备 33010602011771号