Coroutine ( coroutine engleză ) - un modul software , special organizat pentru a asigura interacțiunea cu alte module pe principiul multitasking-ului cooperativ : modulul este suspendat la un anumit punct, salvând starea completă (inclusiv stiva de apeluri și contorul de comenzi ) și transferuri controlul către altul, cel la rândul său, execută sarcina și transferă controlul înapoi, păstrându-și stiva și contorul. Împreună cu fibrele , corutinele sunt un mijloc de furnizare a software-ului multithreading „ușor”, în sensul că pot fi implementate fără utilizarea mecanismelor de schimbare a contextului de către sistemul de operare.
Coroutinele sunt mai flexibile și mai generale decât subrutinele : în comparație cu o subrutină care are întotdeauna un punct de intrare, o corutine are un punct de intrare de pornire și imbricată într-o secvență de retururi urmate de puncte de intrare. O subrutină poate reveni o singură dată, o corutine poate reveni de mai multe ori. Timpul de rulare al unei subrutine este determinat de principiul LIFO (ultimul subprogram numit este finalizat primul), timpul de rulare al unei corutine este determinat de utilizarea și necesitatea acesteia.
Apariția conceptului de corutine este atribuită construcției folosite de Melvin Conway în 1958 în practica programării în limbaj de asamblare [1] , în anii 1960 - 1970, corutinele erau practicate în unele limbaje de nivel înalt ( Klu , Simula , Modula-2 ), dar au câștigat o distribuție notabilă abia în anii 2000, când au apărut numeroase biblioteci de suport pentru coroutine în limbaje de programare populare și unele limbi noi (cum ar fi Lua , Ruby , Go ). , Julia ) au fost construite de la început. Coroutinele sunt folosite pentru a implementa multe componente de program similare, cum ar fi generatoare și iteratoare , liste infinite folosind evaluarea leneșă , conducte , mașini de stare într-o singură subrutină (unde starea este determinată de punctul curent de intrare și ieșire), implementări de gestionare a excepțiilor și modelul actorului .
O parte semnificativă a limbajelor de programare populare , inclusiv C și derivatele ( C++ înainte de C++20 ), nu au suport direct pentru coroutine în limbaj sau în biblioteca standard (acest lucru se datorează, în mare parte, cerințelor pentru o stivă). implementarea subrutinelor).
Într-o situație în care corutinele, ca modalitate naturală de implementare a componentelor, nu sunt disponibile, soluția tipică este de a crea corutine folosind un set de steaguri booleene și alte stări variabile pentru a menține starea externă între invocări. Condițiile din cod fac ca pe apeluri succesive să fie executate diferite secvențe de comenzi, în funcție de valorile variabilelor de stare. O altă soluție tipică este să implementați singur mașina de stare cu o declarație switch mare . Astfel de implementări sunt dificil de susținut și de întreținut.
Fluxurile sunt o alternativă potrivită la coroutine în majoritatea modelelor moderne. Thread-urile oferă capacitatea de a gestiona interacțiunea executării „simultane” a secțiunilor de cod. Prin urmare, este o soluție la probleme mari și complexe, include capabilități complexe puternice și are o complexitate însoțitoare de învățat. Cu toate acestea, în ciuda altor alternative, firele de execuție sunt disponibile pe scară largă în mediul C, sunt familiare majorității programatorilor și sunt în general implementate, documentate și întreținute.
Câteva încercări de a implementa corutine în C:
O abordare folosită pentru a implementa coroutine în limbi fără suport nativ este protothread -urile fără stiva , care oferă un context de blocare în detrimentul mai multor octeți de memorie per fir.
Limbajele de programare funcționale implementează adesea corutine, de exemplu Scheme , Lisp , Haskell . Un număr de limbi au suport încorporat pentru coroutine adăugat în implementările ulterioare, cum ar fi Python (din 2.5 și cu suport sintactic explicit începând cu 3.5), PHP (din 5.5), Kotlin (din 1.1), JavaScript (din 1.7 ). ), C# (din 2.0), Tcl (din 8.6).