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. 두 가지 메서드¶
async def __aenter__(self)는 블록에 진입할 때 실행됩니다. 그것이 반환하는 것이 무엇이든async with의 선택적인as name절이 바인딩하는 대상이 됩니다.self를 반환하는 것이 가장 흔한 형태이지만, 어떤 값이든 동작합니다.async def __aexit__(self, exc_type, exc, tb)는 블록을 빠져나갈 때 실행됩니다.exc_type은 정상 종료 시None이고, 예외(또는 취소) 시에는 예외의 클래스이며exc는 그 인스턴스입니다. 참(truthy) 값을 반환하면 Python에게 예외가 처리되었으며 전파되어서는 안 된다고 알립니다.None(보통의 경우)을 반환하면 정리가 실행된 후 예외가 호출 체인을 따라 계속 올라가도록 합니다.
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.