2.32. Korutine

Korutina je funkcija koja se može zaustaviti na pola izvođenja i kasnije nastaviti od mjesta na kojem je stala, sa svim svojim lokalnim varijablama netaknutima. Odraz je obrasca generatora – tijelo funkcije koje se može privremeno zaustaviti i nastaviti – uz jednu razliku u tome tko upravlja svakim nastavkom.

Pythonova sintaksa za pisanje korutine je par ključnih riječi async / await. async označava funkciju kao korutinu; await označava točke unutar nje na kojima je zaustavljanje dopušteno.

2.32.1. Definiranje korutine

Funkcija definirana s async def je funkcija korutine. Njezin poziv ne izvodi tijelo; ona vraća objekt korutine koji još nije započeo:

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

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

Objekt korutine zaustavljen je na samom početku funkcije. Nešto ga mora pokrenuti kako bi se tijelo izvelo – to nešto je petlja događaja, komponenta izvođenja. MicroPython je isporučuje u modulu asyncio. Za sada, tretirajte korutinu kao „spremnu za pokretanje, koja čeka pokretač”.

2.32.2. Zaustavljanje unutar korutine

Unutar korutine, izraz await privremeno zaustavlja izvođenje sve dok očekivana vrijednost ne bude spremna:

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

Kada tijelo dođe do await read_sensor(), korutina vraća kontrolu onome što je pokreće. Kada read_sensor() završi, pokretač nastavlja korutinu na sljedećoj liniji, s rezultatom vezanim uz data.

await je valjan samo unutar korutine. Njegova upotreba u običnoj funkciji je sintaksna pogreška.

2.32.3. Odnos prema generatorima

Korutine i generatori dijele isti temeljni mehanizam. Razlika je u tome tko povlači svaki nastavak:

  • Generator daje (yield) vrijednosti; potrošač povlači sljedeću pomoću next() ili iteriranjem.

  • Korutina ustupa (yield) kontrolu; petlja događaja zakazuje nastavak kada je očekivana operacija spremna.

Ako vam je rukovanje yield-om kod generatora jasno, rukovanje kod korutine je ista ideja – samo njime upravlja petlja događaja umjesto for petlje.

Petlja događaja je mali raspoređivač koji vodi popis korutina koje čekaju na nešto (mjerač vremena, mrežni događaj, završetak druge korutine). U svakoj iteraciji odabire korutinu čije je čekanje zadovoljeno, nastavlja je do sljedećeg await, zatim bilježi na što ta korutina sada čeka i prelazi na drugu spremnu korutinu. Rezultat je da mnogo zadataka istovremeno napreduje na jednoj niti – svaka korutina dobrovoljno ustupa kontrolu na svojim await točkama, a petlja ispunjava te trenutke bilo kojim drugim korutinama koje su spremne za napredovanje.

Ispod haube, await i yield koriste istu značajku Pythonova izvođenja za zaustavljanje i nastavljanje funkcije. Ključne riječi se razlikuju jer se razlikuje konvencija oko njih: yield vraća vrijednost potrošaču koji povlači pomoću next(); await predaje kontrolu petlji događaja koja zakazuje nastavak kada je očekivana operacija spremna. async / await u biti je novija sintaksa za obrazac korutine – starije biblioteke gradile su korutine izravno na vrhu mehanike generatora, koristeći yield from (predstavljen u Iteratori i generatori) za delegiranje zaustavljanja između korutina.

2.32.4. Korutine trebaju pokretač

Korutina je inertna bez izvođenja koje je pokreće. Definiranje korutine je u redu; njezino pokretanje zahtijeva petlju događaja. MicroPythonov modul asyncio pruža tu petlju događaja. Odjeljak Asyncio pokriva kako pokrenuti petlju, zakazati korutine na njoj, dijeliti stanje među njima pomoću zaključavanja i događaja, rukovati otkazivanjem i istekom vremena te oblikovati stvarnu aplikaciju oko ovdje predstavljenih ključnih riječi async / await.