异步上下文管理器是一个定义了异步方法__aenter__和__aexit__的对象,并在async with结构中使用。这样的管理器用于在异步函数中正确地打开/关闭资源:数据库连接、文件、会话等。
实现示例:
class AsyncDBConnection: async def __aenter__(self): self.conn = await async_db_connect() return self.conn async def __aexit__(self, exc_type, exc, tb): await self.conn.close() async def main(): async with AsyncDBConnection() as conn: await conn.query('SELECT 1')
异步上下文允许在技术延迟中不阻塞事件循环,提高并发程序的性能。
可以在async def中使用普通的with吗?
答案: 是的,但是如果上下文管理器内部的操作使用了awaitable(需要await),则需要使用async with。普通的with不支持异步的enter/exit,会阻塞事件循环,或者如果在enter/exit中调用await会导致失败。
示例:
async def foo(): with open('file.txt') as f: # 这是可以的,同步读取 data = f.read() # 但不能在普通上下文中使用await,只能在async with中
故事
项目: 带有异步API的Web服务。
问题: 数据库连接管理器使用了普通的with,但内部调用了await。这导致了RuntimeError("Cannot use 'await' outside async function")错误,并在生产环境中阻塞了事件循环。
故事
项目: Websockets聊天。
问题: 在处理连接时未关闭websocket资源(使用了普通的同步管理器),这导致了内存泄漏和连接挂起。
故事
项目: 多线程异步任务队列。
问题: 任务管理器未正确实现
__aexit__,忘记返回awaitable。因此,任务的完成不是保证的,部分任务在系统中“挂起”。