8.12. Aszinkron környezetkezelők#
A Python áttekintés bemutatta a környezetkezelőket – azokat az objektumokat, amelyeket a with blokkok vezérelnek, ahol az __enter__ a belépéskor fut, az __exit__ pedig a kilépéskor, függetlenül attól, hogyan ér véget a blokk. Az aszinkron környezetkezelők ugyanaz az ötlet áthelyezve az asyncio világába: az __aenter__ és az __aexit__ korutinok, így a beállítás vagy a tisztítás await-tel várhat valamire. Az őket vezérlő blokk az async with.
Egyet már használtunk is. Az asyncio.Lock egy aszinkron környezetkezelő; a zárak oldal async with bus_lock: ... formában használta. Ez az oldal arról szól, hogyan írjunk egyet egy alkalmazás saját erőforrásához.
8.12.1. Mikor írjunk egyet#
Amikor az alkalmazásnak van egy erőforrása, amely párosított beállítást és lebontást igényel, és legalább az egyik oldalnak await-tel várnia kell valamire. Hálózati kapcsolatok, érzékelők, amelyeknek a konfigurálás után stabilizálódási késleltetés kell, bármi, ami belépéskor lezár valamit és kilépéskor feloldja. Az egyszerű szinkron with forma nem alkalmazható, mert az __enter__ és az __exit__ nem lehet korutin.
8.12.2. A két metódus#
Az
async def __aenter__(self)akkor fut, amikor belépünk a blokkba. Amit visszaad, azt köti azasync withopcionálisas nameága. Aselfvisszaadása a leggyakoribb forma, de bármilyen érték működik.Az
async def __aexit__(self, exc_type, exc, tb)akkor fut, amikor kilépünk a blokkból. Azexc_typeNonenormál kilépéskor; kivétel (vagy megszakítás) esetén ez a kivétel osztálya, azexcpedig a példány. Egy igaz érték visszaadása azt mondja a Pythonnak, hogy a kivétel kezelve lett, és nem szabad továbbterjednie. ANonevisszaadása (a szokásos eset) hagyja, hogy a kivétel a tisztítás lefutása után tovább terjedjen a hívási láncon.
8.12.3. Egy kidolgozott példa#
Egy reflektor-burkoló, amely a blokk törzsének idejére bekapcsol egy LED-et, egy rövid stabilizálódási késleltetéssel, hogy a megvilágítás stabil legyen, mielőtt bármilyen felvétel megtörténne, majd a kilépéskor ismét kikapcsolja a LED-et:
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())
Amikor belépünk a blokkba, lefut az __aenter__: a LED bekapcsol, az 50 ms-os stabilizálódási await átadja a vezérlést a huroknak, hogy más korutinok közben haladhassanak, és a blokk törzse a várakozás befejeztével indul el. Amikor a blokk véget ér – normál kilépéskor, kivétel esetén, vagy megszakításkor –, lefut az __aexit__, és a LED ismét kikapcsol. A tisztítás minden esetben lefut; ezt a garanciát nyújtja az async with.
A képkocka-felvételi oldal bemutatja, hogyan tehetjük a csi.CSI.snapshot() metódust await-baráttá; ha ez a burkoló a kezünkben van, egy async with Spotlight(led): blokk törzse tipikusan egy felvételi hurok lenne, amely az állandó megvilágítás alatt fut.