8.7. 이벤트¶
asyncio.Event는 모듈이 제공하는 가장 단순한 신호 프리미티브입니다. 한 코루틴이 어떤 일이 일어났을 때 이벤트를 설정하고, 다른 임의 개수의 코루틴이 계속 진행하기 전에 이벤트가 설정되기를 기다립니다. 페이로드는 없습니다 – 이벤트는 켜졌다가 무언가가 지울 때까지 켜진 상태로 유지되는 불리언입니다.
8.7.1. 기본 형태¶
import asyncio
async def waiter(evt):
print("waiting")
await evt.wait()
print("got signal")
async def main():
evt = asyncio.Event()
asyncio.create_task(waiter(evt))
await asyncio.sleep(1)
evt.set()
await asyncio.sleep(0)
asyncio.run(main())
대기자 태스크가 실행되어 await evt.wait()에 도달하고 일시 중단됩니다 – 이벤트는 지워진 상태로 시작하므로 wait 호출이 루프로 제어권을 양보합니다. 1초 후 main이 evt.set()을 호출하면 대기자가 재개되도록 스케줄링됩니다. 끝에 있는 await asyncio.sleep(0)은 단지 main이 반환하기 전에 루프가 대기자를 실행할 기회를 갖도록 하는 yield입니다.
8.7.2. 네 가지 메서드¶
8.7.3. 여러 대기자¶
여러 코루틴이 동일한 이벤트를 await할 수 있습니다. 무언가가 set()을 호출하면 그들 모두가 재개되도록 스케줄링됩니다. 이벤트는 기본적으로 일대다이므로, 여러 대기자에게 분산하기 위해 여러 개의 이벤트가 필요하지 않습니다.
8.7.4. 이벤트 재사용¶
흔한 패턴은 이벤트를 반복적으로 사용하는 것입니다 – 신호마다 한 번씩 실행되는 코루틴 – 매번 통과한 후 이벤트를 지움으로써 가능합니다:
async def worker(go):
while True:
await go.wait()
do_one_unit_of_work()
go.clear()
생산자는 작업이 있을 때마다 이벤트를 설정하고, 작업자는 신호를 받아들이면 이를 지웁니다. 작업자가 깨어나기 전에 생산자가 이벤트를 다시 설정할 수 있다면, 작업자는 지우기 전에 그 경우를 처리하고 싶을 수 있습니다(while go.is_set(): ...).
8.7.5. 안전한 컨텍스트¶
Event는 인터럽트 핸들러 내부에서 set()을 호출하기에 안전하지 않습니다. 대기자를 스케줄링하는 데 사용하는 메커니즘은 자신이 이벤트 루프 자체의 컨텍스트 안에서 실행된다고 가정하는데, 인터럽트는 그렇지 않습니다. 인터럽트 핸들러에서 asyncio 태스크를 깨우려면 ThreadSafeFlag(곧 다룸)가 적합한 프리미티브입니다.