8.12. Asynkrona kontexthanterare¶
Python-översikten introducerade kontexthanterare – objekten som with-block driver, med __enter__ som körs på vägen in och __exit__ som körs på vägen ut oavsett hur blocket slutar. Asynkrona kontexthanterare är samma idé flyttad in i asyncio: __aenter__ och __aexit__ är korutiner, så uppsättningen eller städningen kan awaita något. Blocket som driver dem är async with.
Vi har redan använt en. asyncio.Lock är en asynkron kontexthanterare; sidan lås använde den som async with bus_lock: .... Den här sidan handlar om att skriva en för en applikations egen resurs.
8.12.1. När man ska skriva en¶
När applikationen har en resurs som behöver parad uppsättning och nedrivning, och minst en av de sidorna måste awaita något. Nätverksanslutningar, sensorer som behöver en stabiliseringsfördröjning efter konfiguration, allt som låser något vid inträde och låser upp det vid utträde. Den vanliga synkrona with-formen gäller inte eftersom dess __enter__ och __exit__ inte kan vara korutiner.
8.12.2. De två metoderna¶
async def __aenter__(self)körs när blocket inträds. Vad den än returnerar är vad den valfriaas name-satsen iasync withbinds till. Att returneraselfär den vanligaste formen, men vilket värde som helst fungerar.async def __aexit__(self, exc_type, exc, tb)körs när blocket lämnas.exc_typeärNonevid ett normalt utträde; vid ett undantag (eller en avbrytning) är det undantagets klass, ochexcär instansen. Att returnera ett sant värde talar om för Python att undantaget har hanterats och inte ska propagera. Att returneraNone(det vanliga fallet) låter undantaget fortsätta uppåt genom anropskedjan efter att städningen körts.
8.12.3. Ett utarbetat exempel¶
Ett strålkastaromslag som tänder en LED för blockets kropp, med en kort stabiliseringsfördröjning så att belysningen är stabil innan några tagningar sker, och släcker LED:en igen på vägen ut:
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())
När blocket inträds körs __aenter__: LED:en tänds, await för de 50 ms stabilisering lämnar över till loopen så att andra korutiner kan göra framsteg under tiden, och blockets kropp startar när väntan slutförts. När blocket slutar – vid ett normalt utträde, vid ett undantag eller vid avbrytning – körs __aexit__ och LED:en släcks igen. Städningen körs i varje fall; det är garantin som async with ger.
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.