一、基本介绍
Python 的协程(Coroutine)是一种并发编程的解决方案,它允许你以同步的方式编写异步代码。协程在 Python 中是通过 async
和 await
关键字实现的,这些关键字在 Python 3.5 及更高版本中引入。
二、协程的关键点
定义协程:使用 async def
定义一个协程函数。这个函数可以包含 await
表达式,用于等待另一个协程完成。
调用协程:协程函数返回的是一个协程对象,你需要使用 await
来调用它,或者使用 asyncio.run()
来运行最顶层的协程。
等待协程:使用 await
关键字等待另一个协程完成。这会暂停当前协程的执行,直到被等待的协程完成。
事件循环:Python 的 asyncio
库提供了事件循环(Event Loop),它是协程运行和调度的基础设施。
异步函数:异步函数(async def
)可以调用其他异步函数,也可以调用普通的同步函数,但调用同步函数会阻塞事件循环。
异常处理:协程中的异常需要使用 try...except
块来捕获,就像在同步代码中一样。
协程的取消:可以使用 asyncio.cancel()
来取消一个正在运行的协程。
三、简单的协程示例
import asyncio
async def hello():
print('Hello')
await asyncio.sleep(1)
print('World')
async def main():
await hello()
asyncio.run(main())
在这个例子中,hello
是一个协程函数,它打印 "Hello",然后等待一秒,最后打印 "World"。main
函数等待 hello
协程完成。asyncio.run(main())
启动事件循环,运行 main
协程。
四、完整的示例
1. 并发执行多个协程
使用 asyncio.gather
可以并发执行多个协程,并等待它们全部完成。
import asyncio
async def fetch_data(delay):
print(f"开始获取数据,延迟 {delay} 秒")
await asyncio.sleep(delay)
return f"数据 {delay}"
async def main():
task1 = fetch_data(2)
task2 = fetch_data(3)
results = await asyncio.gather(task1, task2)
print(results)
asyncio.run(main())
2. 使用异步上下文管理器
异步上下文管理器允许你在协程中使用 async with
语句。
import asyncio
class AsyncContextManager:
async def __aenter__(self):
print("进入上下文")
return self
async def __aexit__(self, exc_type, exc, tb):
print("退出上下文")
async def main():
async with AsyncContextManager() as manager:
print("在上下文中执行")
asyncio.run(main())
3. 异常处理
在协程中处理异常,确保在异步代码中正确捕获和处理异常。
import asyncio
async def fetch_data():
raise ValueError("数据错误")
async def main():
try:
await fetch_data()
except ValueError as e:
print(f"捕获异常: {e}")
asyncio.run(main())
4. 异步生成器
异步生成器允许你以异步方式生成数据。
import asyncio
async def async_range(n):
for i in range(n):
yield i
await asyncio.sleep(1)
async def main():
async for value in async_range(5):
print(value)
asyncio.run(main())
5. 异步任务组
使用 asyncio.Semaphore
或 asyncio.BoundedSemaphore
来限制并发执行的任务数量。
import asyncio
async def worker(name, semaphore):
async with semaphore:
print(f"工作 {name} 开始")
await asyncio.sleep(2)
print(f"工作 {name} 结束")
async def main():
semaphore = asyncio.Semaphore(2)
tasks = [worker(f"工作 {i}", semaphore) for i in range(5)]
await asyncio.gather(*tasks)
asyncio.run(main())
这些示例展示了 Python 协程在实际应用中的一些高级用法,包括并发执行、上下文管理、异常处理、异步生成器和任务组控制。通过这些技术,你可以编写更高效、更灵活的异步代码。