2.32. Korutiny

Korutina je funkce, kterou lze v půli pozastavit a později obnovit od místa, kde skončila, se všemi jejími lokálními proměnnými nedotčenými. Zrcadlí vzor generátoru – tělo funkce, které lze pozastavit a obnovit – s jednou změnou v tom, kdo řídí každé obnovení.

Python má pro psaní korutiny syntaxi v podobě dvojice klíčových slov async / await. async označuje funkci jako korutinu; await označuje uvnitř ní místa, kde je povoleno pozastavení.

2.32.1. Definice korutiny

Funkce definovaná pomocí async def je funkce korutiny. Její zavolání nespustí tělo; vrátí objekt korutiny, který se ještě nezačal vykonávat:

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

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

Objekt korutiny je pozastaven hned na úplném začátku funkce. Něco ho musí řídit, aby se tělo spustilo – tím něčím je smyčka událostí, runtime komponenta. MicroPython jednu poskytuje v modulu asyncio. Prozatím s korutinou zacházejte jako s „připravenou ke spuštění, čekající na řídicí prvek“.

2.32.2. Pozastavení uvnitř korutiny

Uvnitř korutiny výraz await pozastaví vykonávání, dokud není očekávaná hodnota připravena:

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

Když tělo dosáhne await read_sensor(), korutina předá řízení zpět tomu, co ji spouští. Když read_sensor() skončí, řídicí prvek obnoví korutinu na dalším řádku s výsledkem navázaným na data.

await je platné pouze uvnitř korutiny. Jeho použití v běžné funkci je syntaktická chyba.

2.32.3. Vztah ke generátorům

Korutiny a generátory sdílejí stejný základní mechanismus. Rozdíl je v tom, kdo táhne každé obnovení:

  • Generátor poskytuje hodnoty; konzument táhne další pomocí next() nebo iterací.

  • Korutina poskytuje řízení; smyčka událostí naplánuje obnovení, jakmile je očekávaná operace připravena.

Pokud dává smysl předávací protokol generátoru s yield, předávací protokol korutiny je tatáž myšlenka – jen řízená smyčkou událostí namísto smyčky for.

Smyčka událostí je malý dispečer, který udržuje seznam korutin čekajících na něco (časovač, síťovou událost, dokončení jiné korutiny). V každé iteraci vybere korutinu, jejíž čekání bylo splněno, obnoví ji až do dalšího await, poté zaznamená, na co tato korutina nyní čeká, a přejde na další připravenou. Výsledkem je, že mnoho úloh postupuje souběžně v jediném vlákně – každá korutina dobrovolně předává řízení ve svých bodech await a smyčka tyto okamžiky vyplňuje libovolnými jinými korutinami, které jsou připraveny postoupit.

Pod kapotou await a yield používají stejnou funkci runtime Pythonu pro pozastavení a obnovení funkce. Klíčová slova se liší, protože se liší konvence kolem nich: yield předává hodnotu zpět konzumentovi, který táhne pomocí next(); await předává řízení smyčce událostí, která naplánuje obnovení, jakmile je očekávaná operace připravena. async / await je v podstatě novější syntaxe pro vzor korutiny – starší knihovny stavěly korutiny přímo nad mechanismem generátorů s použitím yield from (zavedeným v Iterátory a generátory) pro delegování pozastavení mezi korutinami.

2.32.4. Korutiny potřebují řídicí prvek

Korutina je bez runtime, který by ji řídil, nečinná. Definovat ji je v pořádku; její spuštění potřebuje smyčku událostí. Modul asyncio MicroPythonu tuto smyčku událostí poskytuje. Sekce Asyncio popisuje, jak smyčku spustit, jak na ní naplánovat korutiny, jak mezi nimi sdílet stav pomocí zámků a událostí, jak zacházet se zrušením a časovými limity a jak kolem zde zavedených klíčových slov async / await utvářet reálnou aplikaci.