Coroutines sunt practic funcții a căror execuție poate fi întreruptă/suspendată într-un anumit punct și apoi putem relua execuția din același punct mai târziu ori de câte ori dorim.

avem nevoie de un mecanism — sau mai precis, un cuvânt cheie — prin care să putem introduce un punct de control și să spunem programului că dorim să întrerupem execuția funcției aici și să returnăm controlul la punctul din care a sunat. Vom relua execuția când vrem.

în Python, putem întrerupe executarea unei funcții folosind cuvântul cheie yield.

deci, iată unde lucrurile devin interesante:

  • ne putem gândi la o coroutină ca la o funcție care are unul sau mai multe puncte de control în care execuția va fi întreruptă și controlul va fi returnat la punctul de unde a fost apelat.
  • în esență, o corutină este o funcție împărțită în mai multe părți și putem executa fiecare parte a unei corutine pe măsură ce executăm fiecare iterație a unei bucle for folosind funcția next.

Iată un exemplu de bază:

OUTPUT :<class 'generator'>
Function Starts
Function Ends

din ieșire, observăm câteva lucruri:

  • în primul rând, avem nevoie pentru a apela coroutine/funcția care ne va da un obiect generator.
  • acel obiect generator se va comporta similar cu un iterator, dar în cazul unui iterator, traversăm peste un iterabil. Cu un generator, executăm părți ale coroutinei.
  • la fel cum o excepție StopIteration este aruncată și prinsă în culisele unei bucle for, același lucru se întâmplă și în acest caz când se execută ultima parte a coroutinei.

acum, această întrerupere a funcției între ele este foarte interesantă și deschide câteva posibilități:

  • când funcția este întreruptă, nu facem nimic, ceea ce tocmai am văzut.
  • să presupunem că o variabilă este modificată de mai multe ori într-o funcție și dorim valoarea acelei variabile particulare la un anumit punct de control. Apoi, când întrerupem această funcție pe acel punct de control special, returnează valoarea acelei variabile.

să vedem un exemplu:

OUTPUT :Function Part 1
5
Function part 2
12
Function part 3

aici, valoarea x este returnată de yield la diferite puncte de control, deoarece execuția funcției a fost întreruptă.

ori de câte ori executăm ultima parte a funcției și nu mai rămâne niciun randament în funcție, după executarea acelei ultime părți, va fi ridicată o excepție StopIteration.

la fel ca atunci când un iterator încearcă să execute următoarea funcție, dar nu mai există elemente rămase în iterabil, ridică și excepția StopIteration.

  • să presupunem că dorim să trimitem o valoare (care poate fi o constantă sau Variabilă) la un anumit punct de control (adică la o anumită stare a unei funcții). De asemenea, putem face acest lucru folosind cuvântul cheie yield. Când dorim să trimitem o valoare, vom folosi funcția sendîn loc de next.

să vedem un exemplu:

OUTPUT :Function part 1
6
Function part 2
12
Function part 3

motivul pentru care am folosit next înainte de a utiliza send este că putem folosi send numai atunci când suntem la punctul de control yield și yield se află în partea dreaptă a expresiei. Deci, pentru a ajunge la primul yield, trebuie să folosim funcția next.

acum vine o aplicație interesantă a coroutinelor. Să presupunem că vrem să comutăm înainte și înapoi între două funcții, așa cum facem în multithreading. În multithreading, până când un interrupt este întâlnit de sistemul de operare, acesta va continua să execute. În acest caz, putem schimba oricând dorim.

să vedem un exemplu:

OUTPUT :Function 1 part 1
Function 2 part 1
Function 1 part 2
Function 1 part 3
Function 2 part 2
Function 2 part 3
Function 2 part 4
Function 1 part 4
Function 1 part 5

în acest exemplu, putem vedea că putem comuta înainte și înapoi între Coroutine ori de câte ori dorim.

deci, dacă scriem propriul nostru planificator personalizat care gestionează comutarea între mai multe Coroutine, putem realiza cu o singură filetare ceea ce facem cu multithreading.

Coroutinele au multe aplicații, cum ar fi concurența și alte modele de programare pot fi, de asemenea, implementate, cum ar fi producător-consumator sau expeditor-receptor în programarea rețelei. Le voi explora în articolele viitoare.

Coroutinele sunt, de asemenea, blocurile de construcție ale multor cadre, cum ar fi asyncio, twisted, aiohttp. Ele pot fi, de asemenea, înlănțuite împreună pentru a face conducte și a rezolva probleme.