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 az async with opcionális as name ága. A self visszaadá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. Az exc_type None normál kilépéskor; kivétel (vagy megszakítás) esetén ez a kivétel osztálya, az exc pedig 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. A None visszaadá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.

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.