2.32. Korutiinit

Korutiini on funktio, joka voi keskeytyä kesken suorituksen ja jatkaa myöhemmin siitä, mihin se jäi, kaikki paikalliset muuttujansa tallessa. Se heijastaa generaattorimallia – funktiorunkoa, jonka voi keskeyttää ja jatkaa – yhdellä erolla siinä, kuka ohjaa kutakin jatkamista.

Pythonin syntaksi korutiinin kirjoittamiseen on avainsanapari async / await. async merkitsee funktion korutiiniksi; await merkitsee sen sisällä kohdat, joissa keskeyttäminen on sallittua.

2.32.1. Korutiinin määrittely

async def -määreellä määritelty funktio on korutiinifunktio. Sen kutsuminen ei suorita runkoa; se palauttaa korutiiniolion, joka ei ole vielä alkanut:

async def greet(name):
    print("hello,", name)

coro = greet("Alice")        # body NOT run yet

Korutiinioilio on keskeytetty heti funktion alussa. Jonkin täytyy ohjata sitä, jotta runko suoritetaan – tuo jokin on tapahtumasilmukka, ajonaikainen komponentti. MicroPython sisältää sellaisen asyncio -moduulissa. Toistaiseksi voit ajatella korutiinin olevan ”valmis suoritettavaksi, odottamassa ohjainta”.

2.32.2. Keskeyttäminen korutiinin sisällä

Korutiinin sisällä await -lauseke keskeyttää suorituksen, kunnes odotettu arvo on valmis:

async def fetch_and_log():
    data = await read_sensor()
    print("got:", data)

Kun runko saavuttaa kohdan await read_sensor(), korutiini luovuttaa hallinnan takaisin sille, mikä sitä suorittaa. Kun read_sensor() valmistuu, ohjain jatkaa korutiinia seuraavalta riviltä, ja tulos sidotaan muuttujaan data.

await on kelvollinen vain korutiinin sisällä. Sen käyttö tavallisessa funktiossa on syntaksivirhe.

2.32.3. Suhde generaattoreihin

Korutiinit ja generaattorit jakavat saman taustamekanismin. Ero on siinä, kuka vetää kunkin jatkamisen:

  • Generaattori tuottaa arvoja; kuluttaja vetää seuraavan funktiolla next() tai iteroimalla.

  • Korutiini luovuttaa hallinnan; tapahtumasilmukka ajoittaa jatkamisen, kun odotettu operaatio on valmis.

Jos generaattorin yield-kättely on selvä, korutiinin kättely on sama ajatus – vain tapahtumasilmukan ohjaamana for -silmukan sijaan.

Tapahtumasilmukka on pieni jakaja, joka ylläpitää listaa korutiineista, jotka odottavat jotakin (ajastinta, verkkotapahtumaa, toisen korutiinin valmistumista). Joka kierroksella se valitsee korutiinin, jonka odotus on täyttynyt, jatkaa sitä seuraavaan await -kohtaan asti, kirjaa sitten mitä tuo korutiini nyt odottaa ja siirtyy toiseen valmiina olevaan. Tuloksena monet tehtävät edistyvät rinnakkain yhdessä säikeessä – kukin korutiini luovuttaa hallinnan vapaaehtoisesti await -kohdissaan, ja silmukka täyttää nuo hetket millä tahansa muulla korutiinilla, joka on valmis edistymään.

Konepellin alla await ja yield käyttävät samaa Pythonin ajonaikaista ominaisuutta funktion keskeyttämiseen ja jatkamiseen. Avainsanat eroavat, koska niitä ympäröivä käytäntö eroaa: yield luovuttaa arvon takaisin kuluttajalle, joka vetää sitä funktiolla next(); await luovuttaa hallinnan tapahtumasilmukalle, joka ajoittaa jatkamisen, kun odotettu operaatio on valmis. async / await on pohjimmiltaan uudempaa syntaksia korutiinimallille – vanhemmat kirjastot rakensivat korutiinit suoraan generaattorikoneiston päälle käyttäen yield from -rakennetta (esitelty sivulla Iteraattorit ja generaattorit) keskeytyksen delegointiin korutiinien välillä.

2.32.4. Korutiinit tarvitsevat ohjaimen

Korutiini on toimeton ilman sitä ohjaavaa ajonaikaista ympäristöä. Sellaisen määrittely on hyvä; sellaisen suorittaminen tarvitsee tapahtumasilmukan. MicroPythonin asyncio -moduuli tarjoaa tuon tapahtumasilmukan. Osio Asyncio käsittelee, miten silmukka käynnistetään, miten korutiineja ajoitetaan siihen, miten tila jaetaan niiden välillä lukoilla ja tapahtumilla, miten käsitellään peruutuksia ja aikakatkaisuja ja miten todellinen sovellus muotoillaan tässä esiteltyjen async / await -avainsanojen ympärille.