异步IO的其他特性
Python 的异步 I/O 功能不仅限于 `async def` 和 `await` 构造。它们还包括其他高级工具,使异步编程更具表现力,并与常规 Python 构造保持一致。
在接下来的部分中,你将探索强大的异步功能,包括异步循环和推导式、`async with` 语句以及异常组。这些功能将帮助你编写更清晰、更易读的异步代码。
异步迭代器、循环和推导式
除了使用 `async` 和 `await` 创建协程外,Python 还提供了 `async for` 构造来遍历异步迭代器。异步迭代器允许你遍历异步生成的数据。在循环运行时,它会将控制权交还给事件循环,以便其他异步任务可以运行。
注意:如需了解有关异步迭代器的更多信息,请参阅 Python 中的异步迭代器和可迭代对象教程。
这一概念的自然扩展是异步生成器。以下是一个生成 2 的幂并在循环和推导式中使用它们的示例:
async def power_of_two(stop=10):i = 0while i < stop:yield 2*ii += 1await asyncio.sleep(5)async def main():g = []async for i in power_of_two(5):g.append(i)print(g)asyncio.run(main())
async for 本身还是顺序执行,但是当前协程会让出控制权。
同步和异步生成器、循环和推导式之间有一个重要的区别。它们的异步对应物并不天生使迭代并发。相反,它们允许事件循环在你使用 `await` 明确让出控制权时,在迭代之间运行其他任务。除非你使用 `asyncio.gather()` 引入并发,否则迭代本身仍然是顺序的。
只有在处理异步迭代器或上下文管理器时,才需要使用 `async for` 和 `async with`,否则普通的 `for` 或 `with` 会引发错误。
异步 with 语句
`with` 语句也有一个异步版本,即 `async with`。这种构造在异步代码中非常常见,因为许多 I/O 密集型任务都涉及设置和清理阶段。
async with 专门用来异步地进入和退出上下文(即 __aenter__ / __aexit__ 协程方法)。
最常见场景:限并发、连接池、自动加解锁、数据库事务等。
以下是一个实现所需功能的示例:
import asyncioclass AsyncLimiter:def __init__(self,max_parallel: int):self.sem = asyncio.Semaphore(max_parallel)async def __aenter__(self):print("__aenter__")await self.sem.acquire()async def __aexit__(self, exc_type, exc_val, exc_tb):print("__aexit__")self.sem.release()async def main():li