登录
首页 >  文章 >  python教程

asyncwith实现异步上下文管理器详解

时间:2026-01-26 10:00:42 309浏览 收藏

“纵有疾风来,人生不言弃”,这句话送给正在学习文章的朋友们,也希望在阅读本文《使用 async with 实现异步上下文管理器》后,能够真的帮助到大家。我也会在后续的文章中,陆续更新文章相关的技术文章,有好的建议欢迎大家在评论留言,非常感谢!

Python中实现异步上下文管理器需用@asynccontextmanager装饰器或自定义类实现__aenter__和__aexit__方法,不可混用同步装饰器与异步函数。

如何让 contextmanager 支持异步上下文管理

Python 的 @contextmanager 装饰器本身不支持异步上下文管理(即不能直接用于 async with),因为它返回的是同步的生成器。要让上下文管理器支持 async with,必须使用 async def 定义,并实现 __aenter____aexit__ 方法——也就是自定义异步上下文管理器类。

用类实现异步上下文管理器

这是最标准、最可控的方式。你需要定义一个类,手动实现两个异步方法:

  • __aenter__:在 async with 进入时被 await,可执行异步初始化(如连接数据库、获取锁)
  • __aexit__:在 async with 结束时被 await,可执行异步清理(如关闭连接、提交/回滚事务)

示例:

class AsyncDBConnection:
    def __init__(self, url):
        self.url = url
        self.conn = None
<pre class="brush:php;toolbar:false"><code>async def __aenter__(self):
    self.conn = await aiomysql.connect(host=self.url)
    return self.conn

async def __aexit__(self, exc_type, exc_val, exc_tb):
    if self.conn:
        await self.conn.close()</code>

使用方式:

async with AsyncDBConnection("localhost") as conn:
    result = await conn.execute("SELECT 1")

用 asynccontextmanager(推荐)

Python 3.7+ 的 contextlib 提供了 @asynccontextmanager 装饰器,语法上最接近 @contextmanager,但专为异步设计。它把异步生成器自动包装成符合 AsyncContextManager 协议的对象。

注意:需从 contextlib 导入,不是 asyncio

from contextlib import asynccontextmanager
<p>@asynccontextmanager
async def lifespan(app):</p><h1>启动前:异步初始化</h1><pre class="brush:php;toolbar:false"><code>database = await connect_db()
cache = await init_cache()
try:
    yield {"db": database, "cache": cache}
finally:
    # 关闭后:异步清理
    await database.close()
    await cache.shutdown()</code>

使用方式相同:

async with lifespan(my_app) as resources:
    await do_something(resources["db"])

不能混用 sync 和 async

以下写法是错误的:

  • @contextmanager + async def —— 会报 TypeError: @contextmanager only works with sync generators
  • __aenter__ 中返回普通(非 awaitable)对象 —— 必须返回 awaitable,否则 async with 会失败
  • 忘记在 __aexit__ 中处理异常或加 await —— 清理逻辑不会真正执行

常见适配场景

很多同步库(如 requestssqlite3)没有原生异步支持。若想封装其资源为异步上下文管理器,需借助线程池或专用异步库:

  • 对阻塞 I/O 操作(如文件读写、HTTP 请求),可用 loop.run_in_executor 包装,再放入 @asynccontextmanager
  • 优先选用已有的异步生态库(如 aiohttpaiomysqlasyncpg),它们通常自带异步上下文管理器
  • FastAPI 的 Depends、Starlette 的 Lifespan 等都依赖 @asynccontextmanager 实现生命周期管理

终于介绍完啦!小伙伴们,这篇关于《asyncwith实现异步上下文管理器详解》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布文章相关知识,快来关注吧!

前往漫画官网入口并下载 ➜
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>