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.