8.12. 异步上下文管理器¶
Python 概览 介绍了上下文管理器——由 with 块驱动的对象,其中 __enter__ 在进入时运行,__exit__ 在退出时运行,无论该块如何结束。异步上下文管理器是同一个理念被移植到 asyncio 中:__aenter__ 和 __aexit__ 是协程,因此其设置或清理可以 await 某些东西。驱动它们的块是 async with。
我们已经用过一个了。asyncio.Lock 就是一个异步上下文管理器;锁 页面就以 async with bus_lock: ... 的形式使用了它。本页讲的是为应用程序自己的资源编写一个异步上下文管理器。
8.12.1. 何时编写它¶
当应用程序拥有一个需要成对进行设置与拆除的资源,并且这两侧中至少有一侧必须 await 某些东西时。例如网络连接、配置后需要一段稳定延迟的传感器、任何在进入时锁定某物并在退出时解锁的东西。普通的同步 with 形式不适用,因为它的 __enter__ 和 __exit__ 不能是协程。
8.12.2. 两个方法¶
8.12.3. 一个实际示例¶
一个聚光灯封装器,它在块的主体期间点亮一个 LED,并带有一段短暂的稳定延迟,使照明在任何采集发生之前都保持稳定,然后在退出时再次熄灭该 LED:
import asyncio
from machine import LED
class Spotlight:
def __init__(self, led):
self._led = led
async def __aenter__(self):
self._led.on()
await asyncio.sleep_ms(50)
return self
async def __aexit__(self, exc_type, exc, tb):
self._led.off()
async def main():
led = LED("LED_WHITE")
async with Spotlight(led):
# work that benefits from steady illumination
await asyncio.sleep_ms(200)
asyncio.run(main())
当进入块时,__aenter__ 运行:LED 点亮,50 ms 的稳定 await 让出控制权给循环,以便其他协程在此期间能够推进,块主体则在该等待完成后开始。当块结束时——无论是正常退出、发生异常、还是被取消——__aexit__ 都会运行并使 LED 重新熄灭。清理在每种情况下都会运行;这正是 async with 所提供的保证。
The frame capture page
shows how to make csi.CSI.snapshot() await-friendly; once that wrapper is in hand, the body of an
async with Spotlight(led): block would typically be a
capture loop running under the steady illumination.