8.7. Tapahtumat¶
asyncio.Event on yksinkertaisin signalointiprimitiivi, jonka moduuli tarjoaa. Yksi korutiini asettaa tapahtuman, kun jotain on tapahtunut; mikä tahansa määrä muita korutiineja odottaa tapahtuman asettamista ennen jatkamista. Hyötykuormaa ei ole – tapahtuma on totuusarvo, joka kääntyy päälle ja pysyy päällä, kunnes jokin tyhjentää sen.
8.7.1. Perusmuoto¶
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())
Odottajatehtävä suoritetaan, osuu await evt.wait() -kutsuun ja keskeytetään – tapahtuma alkaa tyhjennetystä tilasta, joten wait -kutsu luovuttaa vuoron takaisin silmukalle. Sekuntia myöhemmin main kutsuu evt.set() ja odottaja ajastetaan jatkamaan. Lopussa oleva await asyncio.sleep(0) on vain yield, jotta silmukka saa mahdollisuuden suorittaa odottajan ennen kuin main palaa.
8.7.2. Neljä metodia¶
set()– käännä tapahtuma asetetuksi ja ajasta jokainen korutiini, joka on parhaillaan estettynäwait()-kutsussa, jatkamaan. Tapahtuma pysyy asetettuna, kunnes se tyhjennetään.clear()– käännä tapahtuma takaisin tyhjennetyksi. Korutiinit, jotkaawait wait()-odottavat tämän jälkeen, estyvät uudelleen.wait()– korutiini. Jos tapahtuma on jo asetettu, palaa heti. Muuten estyy, kunnes jokin asettaa sen.is_set()– palauttaa nykyisen tilan estymättä. Hyödyllinen, kun korutiini haluaa tarkistaa tapahtuman odottamatta sitä.
8.7.3. Useita odottajia¶
Useat korutiinit voivat awaittaa samaa tapahtumaa. Kun jokin kutsuu set(), ne kaikki ajastetaan jatkamaan. Tapahtuma on oletuksena yksi-moneen; ei ole tarvetta useille tapahtumille, jotka haarautuvat useille odottajille.
8.7.4. Tapahtuman uudelleenkäyttö¶
Yleinen malli on käyttää tapahtumaa toistuvasti – korutiini, joka suoritetaan kerran signaalia kohden – tyhjentämällä se jokaisen läpiajon jälkeen:
async def worker(go):
while True:
await go.wait()
do_one_unit_of_work()
go.clear()
Tuottaja asettaa tapahtuman aina, kun työtä on; työntekijä tyhjentää sen, kun se on poiminut signaalin. Jos tuottaja saattaa asettaa tapahtuman uudelleen ennen kuin työntekijä on herännyt, työntekijä saattaa haluta käsitellä tuon tapauksen (while go.is_set(): ...) ennen tyhjentämistä.
8.7.5. Turvalliset kontekstit¶
Event -luokassa set()-metodia ei ole turvallista kutsua keskeytyskäsittelijän sisältä. Mekanismi, jota se käyttää odottajien ajastamiseen, olettaa toimivansa tapahtumasilmukan oman kontekstin sisällä, mitä keskeytykset eivät ole. Asyncio-tehtävän herättämiseen keskeytyskäsittelijästä ThreadSafeFlag (käsitellään pian) on oikea primitiivi.