Coroutines zijn in principe functies waarvan de uitvoering kan worden onderbroken/opgeschort op een bepaald punt, en dan kunnen we de uitvoering vanaf dat zelfde punt later hervatten wanneer we maar willen.

we hebben een mechanisme nodig — of om preciezer te zijn, een trefwoord-waarmee we een checkpoint kunnen invoegen en het programma kunnen vertellen dat we de uitvoering van de functie hier willen pauzeren en de controle terug willen geven naar het punt dat het heeft aangeroepen. We hervatten de executie wanneer we willen.

in Python kunnen we de uitvoering van een functie pauzeren met het yield sleutelwoord.

hier wordt het interessant:

  • we kunnen een coroutine zien als een functie die een of meer controlepunten heeft waar de uitvoering zal worden onderbroken en de controle zal worden teruggebracht naar het punt waar het werd aangeroepen.
  • in wezen is een coroutine een functie verdeeld in vele delen, en we kunnen elk deel van een coroutine uitvoeren zoals we elke iteratie van een for-lus uitvoeren met behulp van de functie next.

hier is een basisvoorbeeld:

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

aan de output zien we een paar dingen:

  • eerst moeten we de coroutine/functie aanroepen die ons een generatorobject geeft.
  • dat generatorobject zal zich op dezelfde manier gedragen als een iterator, maar in het geval van een iterator, doorkruisen we een iterable. Met een generator voeren we delen van de coroutine uit.
  • net zoals een uitzondering StopIteration achter de schermen van een for-lus wordt gegooid en gevangen, gebeurt hetzelfde in dit geval wanneer het laatste deel van de coroutine wordt uitgevoerd.

dit pauzeren van de functie daartussen is zeer interessant en opent enkele mogelijkheden:

  • wanneer de functie is gepauzeerd, doen we niets, wat het geval is dat we net zagen.
  • stel dat een variabele meerdere keren wordt gewijzigd in een functie en we willen de waarde van die specifieke variabele op een bepaald controlepunt. Als we dan die functie pauzeren op dat specifieke controlepunt, geeft het de waarde van die variabele terug.

laat een voorbeeld zien:

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

hier wordt de waarde x op verschillende controlepunten geretourneerd door yield, omdat de uitvoering van de functie is gepauzeerd.

wanneer we het laatste deel van de functie uitvoeren en er geen rendement meer over is in de functie, zal na het uitvoeren van dat laatste deel een StopIteration uitzondering worden verhoogd.

net als wanneer een iterator probeert de volgende functie uit te voeren, maar er zijn geen elementen meer over in de iterable, het verhoogt ook de uitzondering StopIteration.

  • stel dat we een waarde willen verzenden (die een constante of variabele kan zijn) op een bepaald controlepunt (dat wil zeggen in een bepaalde status van een functie). We kunnen dat ook doen met het yield sleutelwoord. Wanneer we een waarde willen verzenden, gebruiken we de functie send in plaats van next.

laat een voorbeeld zien:

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

de reden dat we next gebruikten voordat we send gebruikten, is dat we send alleen kunnen gebruiken als we op het controlepunt yield staan, en yield aan de rechterkant van de expressie staat. Dus om die eerste yield te bereiken, moeten we de functie next gebruiken.

hier komt een interessante toepassing van coroutines. Stel dat we heen en weer willen schakelen tussen twee functies zoals we doen in multithreading. In multithreading, totdat een interrupt wordt aangetroffen door het besturingssysteem, zal het blijven uitvoeren. In dit geval kunnen we wisselen wanneer we maar willen.

laat een voorbeeld zien:

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

In dit voorbeeld kunnen we zien dat we heen en weer kunnen schakelen tussen coroutines wanneer we maar willen.

dus als we onze eigen aangepaste planner schrijven die het schakelen tussen meerdere coroutines regelt, kunnen we met single threading bereiken wat we doen met multithreading.Coroutines hebben vele toepassingen zoals concurrency en andere programmeerpatronen kunnen ook worden geïmplementeerd, zoals Producent-Consument of afzender-ontvanger in netwerkprogrammering. Ik zal die onderzoeken in komende artikelen.Coroutines zijn ook de bouwstenen van veel frameworks zoals asyncio, twisted, aiohttp. Ze kunnen ook aan elkaar worden geketend om pijpleidingen te maken en problemen op te lossen.