Coroutine ( inglés coroutine ) - un módulo de software , especialmente organizado para garantizar la interacción con otros módulos según el principio de multitarea cooperativa : el módulo se suspende en un punto determinado, guardando el estado completo (incluida la pila de llamadas y el contador de comandos) y transferencias control a otro, el que a su vez ejecuta la tarea y transfiere el control de vuelta, conservando su pila y contador. Junto con las fibras ( eng. fibra ), las corrutinas son un medio para proporcionar subprocesos múltiples de software "ligero".en el sentido de que pueden implementarse sin utilizar los mecanismos de cambios de contexto por parte del sistema operativo.
Las rutinas son más flexibles y generales que las subrutinas : en comparación con una subrutina que siempre tiene un punto de entrada, una rutina tiene un punto de entrada inicial y está anidada dentro de una secuencia de retornos seguida de puntos de entrada. Una subrutina solo puede regresar una vez, una corrutina puede regresar varias veces. El tiempo de ejecución de una subrutina está determinado por el principio LIFO (la última subrutina llamada se completa primero), el tiempo de ejecución de una corrutina está determinado por su uso y necesidad.
El surgimiento del concepto de coroutine se atribuye a la construcción utilizada por Melvin Conway en 1958 en la práctica de programación en lenguaje ensamblador [1] , en las décadas de 1960 y 1970, las coroutines se practicaban en algunos lenguajes de alto nivel ( Klu , Simula , Modula-2 ), pero obtuvieron una distribución notable solo en la década de 2000, cuando aparecieron numerosas bibliotecas de soporte coroutine en lenguajes de programación populares y algunos lenguajes nuevos (como Lua , Ruby , Go , Julia ) se incorporaron desde el principio. Las corrutinas se utilizan para implementar muchos componentes de programas similares, como generadores e iteradores , listas infinitas que usan evaluación diferida , canalizaciones , máquinas de estado dentro de una sola subrutina (donde el estado está determinado por el punto de entrada y salida actual), implementaciones de manejo de excepciones y el actor modelo
Una parte significativa de los lenguajes de programación populares , incluidos C y sus derivados ( C++ antes de C++20 ), no tienen compatibilidad directa con corrutinas en el lenguaje o la biblioteca estándar (esto se debe, en gran parte, a los requisitos de una pila implementación de subrutinas).
En una situación donde las corrutinas, como una forma natural de implementar componentes, no están disponibles, la solución típica es crear corrutinas utilizando un conjunto de banderas booleanas y otros estados variables para mantener el estado externo entre invocaciones. Las condiciones dentro del código hacen que se ejecuten diferentes secuencias de comandos en llamadas sucesivas, según los valores de las variables de estado. Otra solución típica es implementar la máquina de estado usted mismo con una declaración de cambio grande . Tales implementaciones son difíciles de soportar y mantener.
Las secuencias son una alternativa adecuada a las corrutinas en la mayoría de los diseños modernos. Los subprocesos brindan la capacidad de administrar la interacción de ejecutar "simultáneamente" secciones de código. Por lo tanto, es una solución a problemas grandes y complejos, incluye poderosas capacidades complejas y tiene una complejidad que lo acompaña para aprender. Sin embargo, a pesar de otras alternativas, los subprocesos están ampliamente disponibles en el entorno C, son familiares para la mayoría de los programadores y generalmente se implementan, documentan y mantienen.
Algunos intentos de implementar coroutines en C:
Un enfoque utilizado para implementar corrutinas en lenguajes sin soporte nativo son los protothreads sin pila , que proporcionan un contexto de bloqueo a expensas de varios bytes de memoria por hilo.
Los lenguajes de programación funcionales a menudo implementan rutinas, por ejemplo, Scheme , Lisp , Haskell . Una serie de lenguajes han agregado compatibilidad con rutinas integradas en implementaciones posteriores, como Python (desde 2.5 y con soporte sintáctico explícito desde 3.5), PHP (desde 5.5), Kotlin (desde 1.1), JavaScript (desde 1.7 ). ), C# (desde 2.0), Tcl (desde 8.6).