Articulo de referencia

Corutina

Las corrutinas son componentes de programas informáticos que pueden suspenderse y reanudarse —generalizando las subrutinas— para la multitarea cooperativa . Son muy adecuadas pa...

Las corrutinas son componentes de programas informáticos que pueden suspenderse y reanudarse —generalizando las subrutinas— para la multitarea cooperativa . Son muy adecuadas para implementar componentes de programas comunes como tareas cooperativas , excepciones , bucles de eventos , iteradores , listas infinitas y tuberías .

Se las ha descrito como "funciones cuya ejecución se puede pausar". [ 1 ]

Melvin Conway acuñó el término corrutina en 1958 cuando lo aplicó a la construcción de un programa de ensamblaje . [ 2 ] La primera explicación publicada de la corrutina apareció más tarde, en 1963. [ 3 ]

Definición y tipos

No existe una única definición precisa de corrutina. En 1980, Christopher D. Marlin [ 4 ] resumió dos características fundamentales ampliamente reconocidas de una corrutina:

  1. Los valores de los datos locales a una corrutina persisten entre llamadas sucesivas;
  2. La ejecución de una corrutina se suspende cuando el control la abandona, para luego reanudarse donde se interrumpió cuando el control vuelve a entrar en la corrutina en una etapa posterior.

Además, una implementación de corrutina tiene 3 características:

  1. el mecanismo de transferencia de control. Las corrutinas asimétricas suelen proporcionar palabras clave como yieldy resume. Los programadores no pueden elegir libremente a qué marco ceder el control. El entorno de ejecución solo cede el control al llamador más cercano de la corrutina actual. Por otro lado, en las corrutinas simétricas , los programadores deben especificar un destino de cesión de control.
  2. si las corrutinas se proporcionan en el lenguaje como objetos de primera clase , que pueden ser manipulados libremente por el programador, o como construcciones restringidas;
  3. si una corrutina puede suspender su ejecución desde dentro de llamadas a funciones anidadas. Dicha corrutina es una corrutina con pila . Una contraria se llama corrutina sin pila , donde a menos que esté marcada como corrutina, una función regular no puede usar la palabra clave yield.

El artículo "Revisiting Coroutines" [ 5 ] , publicado en 2009, propuso el término corrutina completa para referirse a una que admite corrutinas de primera clase y es apilable. Las corrutinas completas merecen su propio nombre, ya que poseen la misma capacidad expresiva que las continuaciones de un solo uso y las continuaciones delimitadas. Las corrutinas completas pueden ser simétricas o asimétricas. Es importante destacar que el carácter simétrico o asimétrico de una corrutina no influye en su capacidad expresiva, aunque las corrutinas completas son más expresivas que las que no lo son. Si bien su capacidad expresiva es la misma, las corrutinas asimétricas se asemejan más a las estructuras de control basadas en rutinas, en el sentido de que el control siempre se devuelve al invocador, lo que puede resultar más familiar para los programadores.

Comparaciones

Subrutinas

Las subrutinas son casos especiales de corrutinas. [ 6 ] Cuando se invocan las subrutinas, la ejecución comienza desde el principio, y una vez que una subrutina sale, termina; una instancia de una subrutina solo regresa una vez y no mantiene estado entre invocaciones. Por el contrario, las corrutinas pueden salir llamando a otras corrutinas, que luego pueden regresar al punto donde fueron invocadas en la corrutina original; desde el punto de vista de la corrutina, no está saliendo, sino llamando a otra corrutina. [ 6 ] Por lo tanto, una instancia de corrutina mantiene estado y varía entre invocaciones; puede haber múltiples instancias de una corrutina dada a la vez. La diferencia entre llamar a otra corrutina mediante "cederle" el control y simplemente llamar a otra rutina (que entonces también regresaría al punto original), es que la relación entre dos corrutinas que ceden el control entre sí no es de llamador-llamado, sino simétrica.

Cualquier subrutina puede traducirse a una corrutina que no llame a yield . [ 7 ]

Aquí tienes un ejemplo sencillo de cómo pueden ser útiles las corrutinas. Supongamos que tienes una relación productor-consumidor donde una rutina crea elementos y los agrega a una cola, y otra los elimina de la cola y los utiliza. Por razones de eficiencia, quieres agregar y eliminar varios elementos a la vez. El código podría verse así:

q := nueva Cola < Elemento > La corrutina produce un bucle mientras q no está lleno. crear algunos elementos nuevos agregar los artículos a q ceder para consumir Bucle de consumo de corrutina mientras q no esté vacío eliminar algunos elementos de q usar los artículos rendimiento para producir llamar producir

La cola se llena o se vacía por completo antes de ceder el control a la otra corrutina mediante el comando yield . Las siguientes llamadas a corrutinas comienzan justo después de yield , en el bucle de la corrutina externa.

Aunque este ejemplo se usa a menudo como introducción a la programación multihilo , no se necesitan dos hilos para esto: la instrucción yield se puede implementar saltando directamente de una rutina a la otra.

Trapos

Las corrutinas son muy similares a los hilos . Sin embargo, las corrutinas realizan multitarea de forma cooperativa , mientras que los hilos suelen realizar multitarea de forma preventiva . Las corrutinas proporcionan concurrencia , ya que permiten que las tareas se ejecuten fuera de orden o en un orden variable, sin alterar el resultado final, pero no proporcionan paralelismo , puesto que no ejecutan varias tareas simultáneamente. Las ventajas de las corrutinas sobre los hilos son que pueden utilizarse en un contexto de tiempo real estricto ( el cambio entre corrutinas no implica llamadas al sistema ni llamadas bloqueantes de ningún tipo), no se necesitan primitivas de sincronización como mutexes , semáforos, etc., para proteger secciones críticas , y no requieren soporte del sistema operativo.

Es posible implementar corrutinas utilizando hilos programados con prioridad, de una manera que será transparente para el código que las llama, pero se perderán algunas de las ventajas (en particular, la idoneidad para el funcionamiento en tiempo real estricto y el coste relativo de cambiar entre ellas).

Generadores

Los generadores, también conocidos como semicoroutines, [ 8 ] son ​​un subconjunto de las corrutinas. Específicamente, si bien ambos pueden ceder el control varias veces, suspendiendo su ejecución y permitiendo la reentrada en múltiples puntos de entrada, se diferencian en la capacidad de las corrutinas para controlar dónde continúa la ejecución inmediatamente después de ceder el control, mientras que los generadores no pueden, transfiriendo en cambio el control de vuelta a quien los llama. [ 9 ] Es decir, dado que los generadores se utilizan principalmente para simplificar la escritura de iteradores , la yieldinstrucción en un generador no especifica una corrutina a la que saltar, sino que pasa un valor de vuelta a una rutina padre.

Sin embargo, todavía es posible implementar corrutinas sobre una función generadora, con la ayuda de una rutina de despacho de nivel superior (un trampolín , esencialmente) que pasa el control explícitamente a los generadores hijos identificados por los tokens que devuelven los generadores:

q := nueva Cola < Elemento > El generador produce un bucle mientras q no esté lleno. crear algunos elementos nuevos agregar los artículos a q producirEl generador consume el bucle mientras q no esté vacío. eliminar algunos elementos de q usar los artículos producirdespachador de subrutinas d := nuevo Mapa < Generador , Iterador > d[produce] := inicio consume d[consumir] := inicio producir actual := producir llamada de bucle actual actual := siguiente d[actual] llamar al despachador

Varias implementaciones de corrutinas para lenguajes con soporte para generadores pero sin corrutinas nativas (por ejemplo, Python [ 10 ] antes de la versión 2.5) utilizan este modelo o uno similar.

Recursión mutua

El uso de corrutinas para máquinas de estados o concurrencia es similar al uso de recursión mutua con llamadas de cola , ya que en ambos casos el control pasa a una rutina diferente de un conjunto. Sin embargo, las corrutinas son más flexibles y generalmente más eficientes. Dado que las corrutinas ceden el control en lugar de devolverlo, y luego reanudan la ejecución en lugar de reiniciarla desde el principio, pueden mantener el estado, tanto las variables (como en un cierre) como el punto de ejecución, y las cesiones no se limitan a estar en la posición de cola; las subrutinas recursivas mutuas deben usar variables compartidas o pasar el estado como parámetros. Además, cada llamada recursiva mutua de una subrutina requiere un nuevo marco de pila (a menos que se implemente la eliminación de llamadas de cola ), mientras que pasar el control entre corrutinas usa los contextos existentes y se puede implementar simplemente mediante un salto.

Usos comunes

Las corrutinas son útiles para implementar lo siguiente:

  • Máquinas de estados dentro de una única subrutina, donde el estado está determinado por el punto de entrada/salida actual del procedimiento; esto puede resultar en un código más legible en comparación con el uso de goto , y también puede implementarse a través de recursión mutua con llamadas de cola .
  • Modelo de actores para la concurrencia, por ejemplo, en los videojuegos . Cada actor tiene sus propios procedimientos (esto separa lógicamente el código), pero ceden voluntariamente el control a un planificador central, que los ejecuta secuencialmente (esta es una forma de multitarea cooperativa ).
  • Los generadores son útiles para flujos de datos , especialmente de entrada/salida , y para el recorrido genérico de estructuras de datos.  
  • Procesos secuenciales comunicantes donde cada subproceso es una corrutina. Las entradas/salidas del canal y las operaciones de bloqueo generan corrutinas, y un planificador las desbloquea al finalizar. Alternativamente, cada subproceso puede ser el padre del que le sigue en la cadena de datos (o del que le precede, en cuyo caso el patrón se puede expresar como generadores anidados).
  • Comunicación inversa, comúnmente utilizada en software matemático, en la que un procedimiento como un solucionador, un evaluador de integrales, etc., necesita el proceso de uso para realizar un cálculo, como evaluar una ecuación o un integrando.

Soporte nativo

Las corrutinas se originaron como un método del lenguaje ensamblador , pero son compatibles con algunos lenguajes de programación de alto nivel .

Java no tiene soporte nativo ni de biblioteca para corrutinas, pero puede llamar a corrutinas de Kotlin kotlinx.coroutines(aunque esto no es lo ideal y requeriría un envoltorio de Java sobre Kotlin).

Dado que las continuaciones se pueden usar para implementar corrutinas, los lenguajes de programación que las admiten también pueden admitir corrutinas con bastante facilidad.

Implementaciones

A partir de 2003Muchos de los lenguajes de programación más populares, incluidos C y sus derivados, no cuentan con soporte integrado para corrutinas ni en el lenguaje ni en sus bibliotecas estándar. Esto se debe, en gran medida, a las limitaciones de la implementación de subrutinas basada en pila . Una excepción es la biblioteca de C++ Boost.Context , parte de Boost , que admite el intercambio de contexto en ARM, MIPS, PowerPC, SPARC y x86 en POSIX, Mac OS X y Windows. Las corrutinas se pueden crear sobre Boost.Context.

En situaciones donde una corrutina sería la implementación natural de un mecanismo, pero no está disponible, la respuesta típica es usar un cierre : una subrutina con variables de estado ( variables estáticas , a menudo indicadores booleanos) para mantener un estado interno entre llamadas y transferir el control al punto correcto. Las condiciones dentro del código dan como resultado la ejecución de diferentes rutas de código en llamadas sucesivas, según los valores de las variables de estado. Otra respuesta típica es implementar una máquina de estados explícita en forma de una instrucción switch grande y compleja o mediante una instrucción goto , particularmente una goto calculada . Estas implementaciones se consideran difíciles de entender y mantener, y son una motivación para el soporte de corrutinas. 

Los hilos , y en menor medida las fibras , son una alternativa a las corrutinas en los entornos de programación más utilizados hoy en día. Los hilos proporcionan herramientas para gestionar la interacción cooperativa en tiempo real de fragmentos de código que se ejecutan simultáneamente . Están ampliamente disponibles en entornos que admiten C (y son compatibles de forma nativa con muchos otros lenguajes modernos), resultan familiares para muchos programadores y, por lo general, están bien implementados, documentados y cuentan con un buen soporte. Sin embargo, dado que resuelven un problema complejo y de gran envergadura, incluyen numerosas funcionalidades potentes y complejas, lo que conlleva una curva de aprendizaje igualmente difícil. Por lo tanto, cuando solo se necesita una corrutina, el uso de hilos puede resultar excesivo.

Una diferencia importante entre los hilos y las corrutinas es que los hilos suelen programarse de forma preventiva, mientras que las corrutinas no. Dado que los hilos pueden reprogramarse en cualquier momento y ejecutarse simultáneamente, los programas que los utilizan deben tener cuidado con el bloqueo . Por el contrario, como las corrutinas solo pueden reprogramarse en puntos específicos del programa y no se ejecutan simultáneamente, los programas que las utilizan a menudo pueden evitar el bloqueo por completo. Esta propiedad también se cita como una ventaja de la programación asíncrona o basada en eventos .

Dado que las fibras se programan de forma cooperativa, proporcionan una base ideal para implementar las corrutinas mencionadas anteriormente. [ 23 ] Sin embargo, el soporte del sistema para las fibras suele ser insuficiente en comparación con el de los hilos.

do

Para implementar corrutinas de propósito general, se debe obtener una segunda pila de llamadas , una característica que el lenguaje C no admite directamente . Una forma fiable (aunque específica de la plataforma) de lograrlo es usar una pequeña cantidad de ensamblador en línea para manipular explícitamente el puntero de pila durante la creación inicial de la corrutina. Este es el enfoque recomendado por Tom Duff en una discusión sobre sus méritos relativos frente al método utilizado por Protothreads . [ 24 ] En plataformas que proporcionan la llamada al sistema sigaltstack de POSIX , se puede obtener una segunda pila de llamadas llamando a una función springboard desde dentro de un manejador de señales [ 25 ] [ 26 ] para lograr el mismo objetivo en C portable, a costa de cierta complejidad adicional. Las bibliotecas de C que cumplen con POSIX o la Especificación Única de Unix (SUSv3) proporcionaban rutinas como getcontext, setcontext, makecontext y swapcontext , pero estas funciones fueron declaradas obsoletas en POSIX 1.2008. [ 27 ]

Una vez obtenida una segunda pila de llamadas con alguno de los métodos mencionados anteriormente, las funciones `setjmp` y `longjmp` de la biblioteca estándar de C se pueden usar para implementar los cambios entre corrutinas. Estas funciones guardan y restauran, respectivamente, el puntero de pila , el contador de programa , los registros guardados por la llamada y cualquier otro estado interno según lo requiera la ABI , de modo que al regresar a una corrutina después de haber cedido el control se restaura todo el estado que se restauraría al regresar de una llamada a función. Las implementaciones minimalistas, que no utilizan las funciones `setjmp` y `longjmp`, pueden lograr el mismo resultado mediante un pequeño bloque de código ensamblador en línea que intercambia únicamente el puntero de pila y el contador de programa, y ​​sobrescribe todos los demás registros. Esto puede ser significativamente más rápido, ya que `setjmp` y `longjmp` deben almacenar de forma conservadora todos los registros que puedan estar en uso según la ABI, mientras que el método `clobber` permite al compilador almacenar (al volcar a la pila) solo lo que sabe que está realmente en uso.

Debido a la falta de soporte directo del lenguaje, muchos autores han escrito sus propias bibliotecas para corrutinas que ocultan los detalles anteriores. La biblioteca libtask de Russ Cox [ 28 ] es un buen ejemplo de este tipo. Utiliza las funciones de contexto si las proporciona la biblioteca nativa de C; de lo contrario, proporciona sus propias implementaciones para ARM, PowerPC, Sparc y x86. Otras implementaciones notables incluyen libpcl, [ 29 ] coro, [ 30 ] lthread, [ 31 ] libCoroutine, [ 32 ] libconcurrency, [ 33 ] libcoro, [ 34 ] ribs2, [ 35 ] libdill, [ 36 ] libaco, [ 37 ] y libco. [ 26 ]

Además del enfoque general anterior, se han realizado varios intentos para aproximar las corrutinas en C con combinaciones de subrutinas y macros. La contribución de Simon Tatham , [ 38 ] basada en el dispositivo de Duff , es un ejemplo notable del género y es la base de Protothreads e implementaciones similares. [ 39 ] Además de las objeciones de Duff, [ 24 ] los propios comentarios de Tatham proporcionan una evaluación franca de las limitaciones de este enfoque: "Hasta donde yo sé, esta es la peor chapuza en C jamás vista en código de producción serio". [ 38 ] Las principales deficiencias de esta aproximación son que, al no mantener un marco de pila separado para cada corrutina, las variables locales no se conservan entre las cedencias de la función, no es posible tener múltiples entradas a la función y el control solo puede cederse desde la rutina de nivel superior. [ 24 ]

C++

C++20 introdujo corrutinas estandarizadas como funciones sin pila que pueden suspenderse en medio de la ejecución y reanudarse en un punto posterior. El estado suspendido de una corrutina se almacena en el montón. [ 40 ] La implementación de este estándar está en curso, y los compiladores G++ y MSVC actualmente admiten completamente las corrutinas estándar en versiones recientes. [ 41 ] Se agregó una clase generadora para rangos síncronos y de evaluación diferida, , en C++23. [ 42 ] Se introdujo una clase de tarea propia, , en C++26 . [ 43 ] Se invoca usando , que devuelve . [ 44 ]std::generatorstd::execution::taskstd::execution::sync_wait()std::optional<std::tuple<Ts...>>

Este es un ejemplo de corrutinas de C++20 con la std::execution::taskclase de C++26.

importar std ;using std :: optional ; using std :: tuple ; using std :: execution :: task ;tarea < int > agregar ( int a , int b ) noexcept { co_return a + b ; }tarea < int > prueba () { int ret = co_await add ( 1 , 2 ); std :: println ( "Return {}" , ret ); co_return ret ; }int main ( int argc , char * argv []) { optional < tuple < int >> result = std :: execution :: sync_wait ( test ()); std :: println ( "Resultado: {}" , std :: get < 0 > ( result ). value_or ( std :: make_tuple ( -1 )));devolver 0 ; }

DO#

C# 2.0 agregó la funcionalidad de semicoroutine ( generador ) a través del patrón iterador y yieldla palabra clave. [ 45 ] [ 46 ] C# 5.0 incluye soporte para la sintaxis await .

Clojure

Cloroutine es una biblioteca de terceros que proporciona soporte para corrutinas sin pila en Clojure . Está implementada como una macro, dividiendo estáticamente un bloque de código arbitrario en llamadas a variables arbitrarias y emitiendo la corrutina como una función con estado.

D

D implementa corrutinas como su clase de biblioteca estándar core.thread.Fiberpara una fibra . [ 47 ] Un generador ( std.concurrency.Generator) [ 48 ] hace que sea trivial exponer una función de fibra como un rango de entrada ( std.range.interfaces.InputRange) [ 49 ] , haciendo que cualquier fibra sea compatible con los algoritmos de rango existentes.

Ir

Go tiene un concepto integrado de " goroutines ", un tipo de hilo ligero que son procesos independientes y ligeros gestionados por el entorno de ejecución de Go. Se puede iniciar una nueva goroutine usando la palabra clave "go". Cada goroutine tiene una pila de tamaño variable que se puede expandir según sea necesario. Las goroutines generalmente se comunican usando los canales integrados de Go. [ 50 ] [ 51 ] [ 52 ] [ 53 ] Sin embargo, las goroutines no son corrutinas (por ejemplo, los datos locales no persisten entre llamadas sucesivas). [ 54 ]

Java

Existen varias implementaciones de corrutinas en Java . A pesar de las restricciones impuestas por las abstracciones de Java, la JVM no excluye la posibilidad. [ 55 ] Se utilizan cuatro métodos generales, pero dos rompen la portabilidad del código de bytes entre JVM que cumplen con los estándares.

  • JVM modificadas. Es posible crear una JVM parcheada para admitir corrutinas de forma más nativa. Se han creado parches para la JVM Da Vinci . [ 56 ]
  • Código de bytes modificado. La funcionalidad de corrutinas es posible reescribiendo el código de bytes Java regular, ya sea sobre la marcha o en tiempo de compilación. Los kits de herramientas incluyen Javaflow , Java Coroutines y Coroutines .
  • Mecanismos JNI específicos de la plataforma. Estos utilizan métodos JNI implementados en el sistema operativo o en las bibliotecas de C para proporcionar la funcionalidad a la JVM.
  • Abstracciones de hilos. Las bibliotecas de corrutinas implementadas mediante hilos pueden ser pesadas, aunque el rendimiento variará según la implementación de hilos de la JVM.
  • Se pueden llamar corrutinas de Kotlin desde Java, pero como Java no puede " suspend", en su lugar se debe bloquear usando kotlinx.coroutines.runBlocking, exponer una kotlinx.coroutines.CoroutineScopeo kotlinx.coroutines.JobAPI, o (de forma más idiomática) devolver un java.util.concurrent.CompletableFuture.

JavaScript

Desde ECMAScript 2015 , JavaScript tiene soporte para generadores , que son un caso especial de corrutinas. [ 57 ]

Kotlin

Kotlin implementa las corrutinas como parte de una biblioteca propia.

import kotlinx.coroutines.*fun main () = runBlocking { launch { delay ( 1000L ) print ( "¡Hola desde dentro de la corrutina!" ) }imprimir ( "¡Hola mundo!" ) }

Lua

Lua ha admitido corrutinas asimétricas apilables de primera clase desde la versión 5.0 (2003), [ 58 ] en la corrutina de la biblioteca estándar . [ 59 ] [ 60 ]

Módulo-2

Modula-2 , tal como lo define Wirth, implementa corrutinas como parte de la biblioteca estándar SYSTEM.

El procedimiento NEWPROCESS() rellena un contexto a partir de un bloque de código y espacio para una pila como parámetros, y el procedimiento TRANSFER() transfiere el control a una corrutina a partir del contexto de la corrutina como parámetro.

Mononucleosis infecciosa

El entorno de ejecución de lenguaje común de Mono admite continuaciones, [ 61 ] a partir de las cuales se pueden construir corrutinas.

Marco de trabajo .NET

Durante el desarrollo de .NET Framework 2.0, Microsoft amplió el diseño de las API de alojamiento de Common Language Runtime (CLR) para gestionar la programación basada en fibra, teniendo en cuenta su uso en modo fibra para SQL Server. [ 62 ]ICLRTask::SwitchOut Antes del lanzamiento, se eliminó la compatibilidad con el gancho de cambio de tareas debido a limitaciones de tiempo. [ 63 ] En consecuencia, el uso de la API de fibra para cambiar de tarea actualmente no es una opción viable en .NET Framework.

OCaml

OCaml admite corrutinas a través de su Threadmódulo. [ 64 ] Estas corrutinas proporcionan concurrencia sin paralelismo y se programan de forma preventiva en un único hilo del sistema operativo. Desde OCaml 5.0, también están disponibles los hilos ligeros , proporcionados por diferentes módulos.

Perl

  • Coro

Las corrutinas están implementadas de forma nativa en todos los backends de Raku . [ 65 ]

PHP

  • Fibras nativas desde PHP 8.1
  • Amphp
  • Lana abierta
  • Corrutina implementada de una manera que se asemeja a las funciones de Python y algunas de Go , muchos ejemplos que muestran su código convertido con el mismo número de líneas y comportamiento.

Pitón

Python tiene soporte para corrutinas usando la asyncio.create_task()función. [ 66 ]

  • Python 2.5 implementa un mejor soporte para la funcionalidad tipo corrutina, basado en generadores extendidos ( PEP 342 ).
  • Python 3.3 mejora esta capacidad, al admitir la delegación a un subgenerador ( PEP 380 ).
  • Python 3.4 introduce un marco integral de E/S asíncrona, estandarizado en PEP 3156 , que incluye corrutinas que aprovechan la delegación de subgeneradores.
  • Python 3.5 introduce soporte explícito para corrutinas con sintaxis async/ await ( PEP 0492 ).
  • Desde Python 3.7, async/await se han convertido en palabras clave reservadas. [ 67 ]
  • Eventlet
  • Vireillo
  • gevent
  • Python sin pila
import asyncio import time from asyncio import Taskasync def main () -> None : task1 : Task [ str ] = asyncio . create_task ( say_after ( 1 , "hello" )) task2 : Task [ str ] = asyncio . create_task ( say_after ( 2 , "world" ))print ( f "iniciado a las { time.strftime ( ' % X ' ) } " )# Esperar hasta que ambas tareas se completen (debería tardar unos 2 segundos) esperar tarea1 esperar tarea2print ( f "terminado a las { time.strftime ( ' % X ' ) } " )

Raqueta

Racket proporciona continuaciones nativas, con una implementación trivial de corrutinas disponible en el catálogo oficial de paquetes. Implementación de S. De Gabrielle.

Rubí

  • Ruby 1.9 admite corrutinas de forma nativa, las cuales se implementan como fibras , que son semicorrutinas. [ 68 ]
  • Una implementación de Marc De Scheemaecker
  • Ruby 2.5 y versiones superiores admiten corrutinas de forma nativa, las cuales se implementan como fibras.
  • Una implementación de Thomas W. Branson

Esquema

Dado que Scheme ofrece soporte completo para continuaciones, implementar corrutinas es prácticamente trivial, requiriendo únicamente el mantenimiento de una cola de continuaciones.

Charla informal

Dado que, en la mayoría de los entornos Smalltalk , la pila de ejecución es un elemento fundamental, las corrutinas se pueden implementar sin necesidad de bibliotecas adicionales ni soporte de la máquina virtual.

Tcl

Desde la versión 8.6, Tcl admite corrutinas en el lenguaje principal. [ 69 ]

Vala

Vala implementa soporte nativo para corrutinas. Están diseñadas para usarse con un bucle principal GTK, pero pueden usarse solas si se tiene cuidado de asegurar que la función de devolución de llamada final nunca tenga que ejecutarse antes de realizar, al menos, una instrucción yield.

lenguajes ensamblador

Los lenguajes ensamblador dependientes de la máquina suelen proporcionar métodos directos para la ejecución de corrutinas. Por ejemplo, en MACRO-11 , el lenguaje ensamblador de la familia de minicomputadoras PDP-11 , el cambio de corrutina "clásico" se realiza mediante la instrucción "JSR PC,@(SP)+", que salta a la dirección extraída de la pila y coloca la dirección de la instrucción actual ( es decir, la de la siguiente ) en la pila. En VAXen (en VAX MACRO ), la instrucción comparable es "JSB @(SP)+". Incluso en un Motorola 6809 existe la instrucción "JSR [,S++]"; nótese el "++", ya que se extraen 2 bytes (de la dirección) de la pila. Esta instrucción se utiliza mucho en el monitor estándar Assist 09.

Véase también

  • Async/await
  • Pipeline , un tipo de corrutina utilizada para la comunicación entre programas [ 70 ].
  • Protothreads , una implementación de hilos ligera y sin pila que utiliza un mecanismo similar al de las corrutinas.

Referencias

  1. "¿Cómo diablos funciona async/await en Python 3.5?" . Tall, Snarky Canadian . 11/02/2016. Archivado del original el 10/01/2023 . Consultado el 10/01/2023 .
  2. Knuth, Donald Ervin (1997). Algoritmos fundamentales (PDF) . El arte de la programación informática. Vol. 1 (3.ª ed.). Addison-Wesley. Sección 1.4.5: Historia y bibliografía, págs. 229. ISBN    978-0-201-89683-1Archivado (PDF) del original el 21/10/2019 .
  3. Conway, Melvin E. (julio de 1963). "Diseño de un compilador de diagramas de transición separables" ( PDF) . Communications of the ACM . 6 (7). ACM: 396–408 . doi : 10.1145/366663.366704 . ISSN 0001-0782 . S2CID 10559786. Archivado (PDF) del original el 6 de abril de 2022. Recuperado el 21 de octubre de 2019 a través de la Biblioteca Digital de ACM.  
  4. Marlin, Christopher (1980). Coroutines: A Programming Methodology, a Language Design and an Implementation . Springer. ISBN 3-540-10256-6.
  5. Ana Lucia de Moura; Roberto Ierusalimschy (2009). "Revisiting Coroutines". ACM Transactions on Programming Languages ​​and Systems . 31 (2): 1– 31. CiteSeerX 10.1.1.58.4017 . doi : 10.1145/1462166.1462167 . S2CID 9918449 .  
  6. 1 2 Knuth, Donald Ervin (1997). Algoritmos fundamentales . El arte de la programación informática. Vol. 1 (3.ª ed.). Addison-Wesley. Sección 1.4.2: Corrutinas, págs. 193-200. ISBN    978-0-201-89683-1.
  7. Perlis, Alan J. (septiembre de 1982). "Epigramas sobre programación" . ACM SIGPLAN Notices . 17 (9): 7–13 . doi : 10.1145/947955.1083808 . S2CID 20512767. Archivado del original el 17 de enero de 1999. 6. La simetría es un concepto que reduce la complejidad (las corrutinas incluyen subrutinas); búscala en todas partes. 
  8. Anthony Ralston (2000). Enciclopedia de la informática . Nature Pub. Group. ISBN 978-1-56159-248-7. Consultado el 11 de mayo de 2013 .
  9. Véase, por ejemplo, The Python Language Reference ( Archivado el 24/10/2012 en Wayback Machine ) " https://docs.python.org/reference/expressions.html#yieldexpr (Archivado el 26/10/2012 en Wayback Machine 5.2.10. Yield expressions]): "Todo esto hace que las funciones generadoras sean bastante similares a las corrutinas; ceden el control varias veces, tienen más de un punto de entrada y su ejecución puede suspenderse. La única diferencia es que una función generadora no puede controlar dónde debe continuar la ejecución después de ceder el control; el control siempre se transfiere a quien llama al generador."
  10. Mertz, David (1 de julio de 2002). "Máquinas de estados basadas en generadores" . Charming Python . IBM developerWorks. Archivado del original el 28 de febrero de 2009. Recuperado el 2 de febrero de 2011 .
  11. "Coroutine: Coroutines con tipado seguro que utilizan tipos de sesión ligeros" . Archivado del original el 20 de enero de 2013. Consultado el 18 de diciembre de 2008 .
  12. "Coroutines en Haskell" . Archivado del original el 9 de enero de 2020. Consultado el 13 de enero de 2019 .
  13. "El módulo de corrutinas (coroutines.hhf)" . Manual de la biblioteca estándar de HLA . Archivado del original el 27 de abril de 2019. Consultado el 4 de diciembre de 2013 .
  14. "Novedades en JavaScript 1.7" . Archivado del original el 8 de marzo de 2009. Consultado el 18 de junio de 2018 .
  15. "Manual de Julia - Flujo de control - Tareas (también conocidas como Corrutinas)" . Archivado del original el 23/01/2021 . Consultado el 10/02/2021 .
  16. "Novedades de Kotlin 1.1" . Archivado del original el 11 de agosto de 2019. Consultado el 27 de febrero de 2017 .
  17. "Manual de referencia de Lua 5.2" . www.lua.org . Archivado del original el 13 de enero de 2018. Consultado el 19 de junio de 2012 .
  18. "Tutorial de Python async/await" . Stack Abuse . 17 de diciembre de 2015. Archivado del original el 29 de noviembre de 2019. Consultado el 21 de octubre de 2019 .
  19. "8. Sentencias compuestas — Documentación de Python 3.8.0" . docs.python.org . Archivado del original el 27/11/2019 . Consultado el 11/03/2016 .
  20. "Gather and/or Coroutines" . 19 de diciembre de 2012. Archivado del original el 13 de junio de 2020. Consultado el 8 de junio de 2015 .
  21. Dahl, OJ; Hoare, CAR, eds. (1972). «Estructuras jerárquicas de programas». Programación estructurada . Londres, Reino Unido: Academic Press. pp. 175–220 . ISBN  978-0-12-200550-3.
  22. McCartney, J. "Repensando el lenguaje de programación de música por computadora: SuperCollider" . Computer Music Journal, 26(4):61-68. MIT Press, 2002.
  23. Implementación de corrutinas para .NET mediante el envoltorio de la API de fibra no administrada. Archivado el 7 de septiembre de 2008 en Wayback Machine , Ajai Shankar, Revista MSDN.
  24. 1 2 3 "Coroutines in C – brainwagon" . 5 de marzo de 2005. Archivado del original el 23 de julio de 2019. Recuperado el 7 de agosto de 2018 .
  25. Ralf S. Engelschall (18–23 de junio de 2000). Multihilo portátil: el truco de la pila de señales para la creación de hilos en el espacio de usuario (PS) . Conferencia Técnica Anual de USENIX. San Diego, EE. UU. Archivado del original el 31 de octubre de 2019. Recuperado el 27 de noviembre de 2017 .
  26. 1 2 "libco" . code.byuu.org .
  27. "getcontext(3) - Página del manual de Linux" . man7.org . Archivado del original el 27/11/2019 . Consultado el 22/11/2017 .
  28. http://swtch.com/libtask/ Archivado el 15/11/2019 en Wayback Machine : la biblioteca de corrutinas libtask de Russ Cox para FreeBSD, Linux, Mac OS X y SunOS.
  29. Biblioteca de corrutinas portátil archivada el 14/12/2005 en Wayback Machine - Biblioteca C que utiliza las funcionalidades de POSIX/SUSv3
  30. http://www.goron.de/~froese/coro/ Archivado el 10/01/2006 en Wayback Machine : la biblioteca coro de Edgar Toernig para x86, Linux y FreeBSD
  31. https://github.com/halayli/lthread Archivado el 13/06/2020 en Wayback Machine - lthread es una biblioteca de corrutinas multinúcleo/multihilo escrita en C
  32. "libcoroutine: Una implementación portátil de corrutinas" . Archivado del original el 12/11/2019 . Consultado el 06/09/2013 .para FreeBSD, Linux, OS X PPC y x86, SunOS, Symbian y otros
  33. "libconcurrency - Una biblioteca de concurrencia escalable para C" .una sencilla biblioteca C para corrutinas portátiles con cambio de pila
  34. "libcoro: biblioteca C que implementa corrutinas (multitarea cooperativa) de forma portable" . Archivado del original el 2 de diciembre de 2019. Consultado el 17 de abril de 2008 .Se utilizó como base para el módulo Perl Coro.
  35. "RIBS (Robust Infrastructure for Backend Systems) versión 2: aolarchive/ribs2" . 13 de agosto de 2019. Archivado del original el 22 de abril de 2020. Recuperado el 21 de octubre de 2019 a través de GitHub.
  36. "libdill" . libdill.org . Archivado del original el 2 de diciembre de 2019. Consultado el 21 de octubre de 2019 .
  37. "Una biblioteca de corrutinas asimétricas en C ultrarrápida y ligera 💎 ⛅🚀⛅🌞: hnes/libaco" . 21 de octubre de 2019. Archivado del original el 29 de noviembre de 2018. Recuperado el 16 de octubre de 2018 a través de GitHub.
  38. 1 2 Simon Tatham (2000). "Coroutines in C" . Archivado del original el 09-11-2019 . Recuperado el 19-09-2003 .
  39. "Implementación de corrutinas sin pila en C y C++: jsseldenthuis/coroutine" . 18 de marzo de 2019. Archivado del original el 13 de junio de 2020. Recuperado el 18 de marzo de 2019 a través de GitHub.
  40. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4680.pdf Archivado el 30/06/2024 en Wayback Machine - Especificación técnica para corrutinas
  41. https://en.cppreference.com/w/cpp/compiler_support#cpp20 Archivado el 8 de agosto de 2022 en Wayback Machine - Compatibilidad actual del compilador con corrutinas estándar
  42. cppreference.com. "std::generator" . cppreference.com . cppreference.com . Consultado el 5 de abril de 2026 .
  43. Dietmar Kühl, Maikel Nadolski (18 de mayo de 2025). "Agregar un tipo de tarea de corrutina" (PDF) . open-std.org . WG21.
  44. cppreference.com. "std::execution::sync_wait" . cppreference.com . cppreference.com . Consultado el 15 de febrero de 2026 .
  45. Wagner, Bill (11 de noviembre de 2021). "Iteradores" . Documentación de C# . Microsoft . Archivado del original el 11 de abril de 2024. Recuperado el 16 de febrero de 2023 a través de Microsoft Learn.
  46. Wagner, Bill (13 de febrero de 2023). "La historia de C#" . Documentación de C# . Microsoft . Versión 2.0 de C#. Archivado del original el 28 de abril de 2023. Recuperado el 16 de febrero de 2023 a través de Microsoft Learn.
  47. Sean Kelly; Walter Bright; Alex Rønne Petersen; Martin Nowak. "Clase core.thread.fiber.Fiber" . dlang.org . dlang.org . Consultado el 5 de abril de 2026 .
  48. Sean Kelly; Alex Rønne Petersen; Martin Nowak. "Clase std.concurrency.Generator" . dlang.org . Fundación del Lenguaje D. Consultado el 5 de abril de 2026 .
  49. Andrei Alexandrescu; David Simcha; Jonathan M Davis. "Interface std.range.interfaces.InputRange" . dlang.org . D Language Foundation . Consultado el 5 de abril de 2026 .
  50. "Goroutines - Go efectivo" . go.dev . Archivado del original el 27 de junio de 2024. Consultado el 28 de noviembre de 2022 .
  51. "Declaraciones de Go - La especificación de Go" . go.dev . Archivado del original el 27/11/2022 . Consultado el 28/11/2022 .
  52. "Goroutines - Un recorrido por Go" . go.dev . Archivado del original el 26 de junio de 2024. Consultado el 28 de noviembre de 2022 .
  53. "Preguntas frecuentes (FAQ) - El lenguaje de programación Go" . go.dev . Archivado del original el 22/11/2021 . Consultado el 28/11/2022 .
  54. "Coroutines for Go" . swtch.com . Archivado del original el 28 de septiembre de 2024. Consultado el 24 de octubre de 2024 .
  55. Lukas Stadler (2009). "JVM Continuations" (PDF) . JVM Language Summit. Archivado (PDF) del original el 23 de abril de 2012. Recuperado el 3 de octubre de 2011 .
  56. Remi Forax (19 de noviembre de 2009). "¡Santo cielo!: la JVM tiene corrutinas/continuación/fibras, etc." . Archivado del original el 19 de marzo de 2015.
  57. "ECMAScript 6: Nuevas características: Descripción general y comparación - Protocolo iterador de función generadora" . es6-features.org . Archivado del original el 18 de marzo de 2018. Consultado el 19 de marzo de 2018 .
  58. "Historial de versiones de Lua" . Lua.org . Archivado del original el 6 de mayo de 2023. Consultado el 24 de abril de 2023 .
  59. de Moura, Ana Lucía; Rodríguez, Noemí; Jerusalén, Roberto. "Corrutinas en Lua" (PDF) . Lua.org . Archivado (PDF) desde el original el 19 de marzo de 2023 . Consultado el 24 de abril de 2023 .
  60. de Moura, Ana Lucía; Rodríguez, Noemí; Jerusalén, Roberto (2004). "Corrutinas en Lua". Revista de Informática Universal . 10 (7): 901--924.
  61. https://www.mono-project.com/Continuations Archivado el 25/11/2010 en Wayback Machine Mono Continuations
  62. http://blogs.msdn.com/cbrumme/archive/2004/02/21/77595.aspx Archivado el 21/12/2007 en Wayback Machine , Chris Brumme, Blog de cbrumme Archivado el 11/12/2007 en Wayback Machine
  63. kexugit (15 de septiembre de 2005). "El modo fibra ha desaparecido..." docs.microsoft.com . Archivado del original el 8 de junio de 2021. Consultado el 8 de junio de 2021 .
  64. "La biblioteca de hilos" . Archivado del original el 25/01/2023 . Consultado el 25/01/2023 .
  65. "RFC #31" . Archivado del original el 4 de septiembre de 2014. Consultado el 30 de agosto de 2014 .
  66. "Coroutines and Tasks" . Documentación de Python . Consultado el 31 de octubre de 2025 .
  67. "Novedades de Python 3.7" . Archivado del original el 28 de noviembre de 2019. Consultado el 10 de septiembre de 2021 .
  68. "semicoroutines" . Archivado del original el 24 de octubre de 2007.
  69. "Página del manual de corrutinas - Comandos integrados de Tcl" . Tcl.tk. Archivado del original el 2 de octubre de 2016. Consultado el 27 de junio de 2016 .
  70. Ritchie, Dennis M. (1980). "La evolución del sistema de tiempo compartido Unix". Diseño de lenguajes y metodología de programación . Notas de clase en ciencias de la computación. Vol. 79. págs. 25–35 . doi : 10.1007/3-540-09745-7_2 . ISBN   978-3-540-09745-7. S2CID 571269 . Archivado del original el 08-04-2015 . Recuperado el 26-01-2011 . 

Lecturas adicionales

  • Ana Lucia de Moura; Roberto Ierusalimschy (2004). "Revisiting Coroutines". ACM Transactions on Programming Languages ​​and Systems . 31 (2): 1– 31. CiteSeerX 10.1.1.58.4017 . doi : 10.1145/1462166.1462167 . S2CID 9918449 .  
  • Introducción completa a las corrutinas orientada al lenguaje C, de Simon Tatham.
  • Página de corrutinas de Softpanorama : contiene numerosos enlaces a corrutinas de ensamblador.