Las corrutinas son componentes de programas informáticos que permiten suspender y reanudar la ejecución, generalizando subrutinas para la multitarea cooperativa . Las corrutinas son adecuadas para implementar componentes de programas familiares, como tareas cooperativas , excepciones , bucles de eventos , iteradores , listas infinitas y tuberías .
Se han 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 ensamblador . [2] La primera explicación publicada de la corrutina apareció más tarde, en 1963. [3]
Definición y tipos
No existe una definición precisa de corrutina. En 1980, Christopher D. Marlin [4] resumió dos características fundamentales ampliamente reconocidas de una corrutina:
- los valores de los datos locales de una corrutina persisten entre llamadas sucesivas;
- La ejecución de una corrutina se suspende cuando el control la abandona, solo para continuar donde se dejó cuando el control vuelve a ingresar a la corrutina en alguna etapa posterior.
Además de eso, una implementación de corrutina tiene 3 características:
- el mecanismo de transferencia de control. Las corrutinas asimétricas suelen proporcionar palabras clave como
yieldyresume. Los programadores no pueden elegir libremente a qué marco ceder. El entorno de ejecución solo cede al llamador más cercano de la corrutina actual. Por otro lado, en las corrutinas simétricas , los programadores deben especificar un destino de rendimiento. - 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;
- Si una corrutina puede suspender su ejecución desde dentro de llamadas de función anidadas. Una corrutina de este tipo es una corrutina apilada . Las que son lo contrario se denominan corrutinas sin pila , donde, a menos que se marquen 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 denotar una que admita corrutinas de primera clase y sea apilable. Las corrutinas completas merecen su propio nombre ya que tienen el mismo poder expresivo que las continuaciones de una sola ejecución y las continuaciones delimitadas. Las corrutinas completas son simétricas o asimétricas. Es importante destacar que el hecho de que una corrutina sea simétrica o asimétrica no tiene relación con su expresividad, ya que son igualmente expresivas, aunque las corrutinas completas son más expresivas que las corrutinas no completas. Si bien su poder expresivo es el mismo, las corrutinas asimétricas se parecen 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.
Comparación con
Subrutinas
Las subrutinas son casos especiales de corrutinas. [6] Cuando se invocan subrutinas, la ejecución comienza desde el principio y, una vez que una subrutina sale, termina; una instancia de una subrutina solo retorna una vez y no mantiene el estado entre invocaciones. Por el contrario, las corrutinas pueden salir llamando a otras corrutinas, que pueden volver más tarde al punto en el que 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 el 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" y simplemente llamar a otra rutina (que, entonces, también, volvería al punto original), es que la relación entre dos corrutinas que ceden ante la otra no es la de llamador-llamado, sino simétrica.
Cualquier subrutina puede traducirse a una corrutina que no llame a yield . [7]
A continuación se muestra un ejemplo sencillo de cómo pueden resultar útiles las corrutinas. Supongamos que tiene una relación consumidor-productor en la que una rutina crea elementos y los añade a una cola y otra elimina elementos de la cola y los utiliza. Por razones de eficiencia, desea añadir y eliminar varios elementos a la vez. El código podría tener este aspecto:
var q := nueva cola
La corrutina produce
un bucle
mientras q no esté lleno
Crea algunos elementos nuevos
Añade los elementos a q
ceder para consumir
La corrutina consume
un bucle
mientras q no esté vacío
eliminar algunos elementos de q
utiliza los articulos
ceder para producir
Llamar a producir
Luego, la cola se llena o se vacía por completo antes de ceder el control a la otra corrutina mediante el comando yield . Las llamadas a otras corrutinas comienzan justo después del comando yield , en el bucle de corrutina externo.
Aunque este ejemplo se utiliza a menudo como introducción al multihilo , no se necesitan dos hilos para esto: la declaración de rendimiento se puede implementar mediante un salto directo de una rutina a la otra.
Trapos
Las corrutinas son muy similares a los hilos . Sin embargo, las corrutinas son multitarea cooperativa , mientras que los hilos son típicamente multitarea preventiva . Las corrutinas proporcionan concurrencia , porque permiten que las tareas se realicen fuera de orden o en un orden modificable, sin cambiar el resultado general, pero no proporcionan paralelismo , porque no ejecutan múltiples tareas simultáneamente. Las ventajas de las corrutinas sobre los hilos son que pueden usarse en un contexto de tiempo real estricto ( el cambio entre corrutinas no necesita involucrar ninguna llamada al sistema o ninguna llamada de bloqueo de ningún tipo), no hay necesidad de primitivas de sincronización como mutexes , semáforos, etc. para proteger secciones críticas , y no hay necesidad de soporte del sistema operativo.
Es posible implementar corrutinas usando subprocesos programados preventivamente, de una manera que sea transparente para el código que los llama, pero se perderán algunas de las ventajas (particularmente la idoneidad para operaciones en tiempo real estricto y la relativa economía de cambiar entre ellos).
Generadores
Los generadores, también conocidos como semicorrutinas, [8] son un subconjunto de las corrutinas. Específicamente, si bien ambos pueden ceder varias veces, suspendiendo su ejecución y permitiendo el reingreso en múltiples puntos de entrada, difieren en la capacidad de las corrutinas para controlar dónde continúa la ejecución inmediatamente después de que ceden, mientras que los generadores no pueden, en su lugar transfieren el control nuevamente al llamador del generador. [9] Es decir, dado que los generadores se utilizan principalmente para simplificar la escritura de iteradores , la yielddeclaración en un generador no especifica una corrutina a la que saltar, sino que pasa un valor de regreso a una rutina padre.
Sin embargo, aún es posible implementar corrutinas sobre una función generadora, con la ayuda de una rutina despachadora de nivel superior (un trampolín , esencialmente) que pasa el control explícitamente a los generadores secundarios identificados por tokens que pasan de vuelta desde los generadores:
var q := nueva cola
El generador produce
un bucle
mientras q no esté lleno
Crea algunos elementos nuevos
Añade los elementos a q
producir
El generador consume
el bucle
mientras q no esté vacío
eliminar algunos elementos de q
utiliza los articulos
producir
despachador
de subrutinas var d := new dictionary( generador → iterador )
d[producir] := iniciar consumir
d[consumir] := iniciar producir
var actual := producir
bucle
llamar actual
actual := siguiente d[actual]
despachador
de llamadas
Varias implementaciones de corrutinas para lenguajes con soporte de generador pero sin corrutinas nativas (por ejemplo, Python [10] antes de 2.5) utilizan este modelo o uno similar.
Recursión mutua
El uso de corrutinas para máquinas de estado o concurrencia es similar al uso de recursión mutua con llamadas de cola , ya que en ambos casos el control cambia a una rutina diferente de un conjunto de rutinas. Sin embargo, las corrutinas son más flexibles y generalmente más eficientes. Dado que las corrutinas ceden en lugar de regresar, y luego reanudan la ejecución en lugar de reiniciar desde el principio, pueden mantener el estado, ambas variables (como en un cierre) y el punto de ejecución, y los rendimientos no se limitan a estar en la posición de cola; las subrutinas mutuamente recursivas deben usar variables compartidas o pasar el estado como parámetros. Además, cada llamada mutuamente recursiva 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 sola 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 concurrencia de actores, por ejemplo en los videojuegos . Cada actor tiene sus propios procedimientos (esto nuevamente separa lógicamente el código), pero ceden voluntariamente el control al planificador central, que los ejecuta secuencialmente (esta es una forma de multitarea cooperativa ).
- Generadores , que son útiles para transmisiones (particularmente de entrada/salida) y para el recorrido genérico de estructuras de datos.
- Comunicación de procesos secuenciales en los que cada subproceso es una corrutina. Las entradas/salidas de canal y las operaciones de bloqueo generan corrutinas y un programador las desbloquea en los eventos de finalización. Alternativamente, cada subproceso puede ser el padre del que lo sigue en la secuencia de datos (o lo precede, en cuyo caso el patrón se puede expresar como generadores anidados).
- Comunicación inversa, comúnmente utilizada en software matemático, en donde un procedimiento como un solucionador, un evaluador integral, ... necesita que el proceso de uso realice un cálculo, como evaluar una ecuación o un integrando.
Soporte nativo
Las corrutinas se originaron como un método de lenguaje ensamblador , pero son compatibles con algunos lenguajes de programación de alto nivel .
- Aikido
- Escritura de ángel
- Bailarina
- BCP
- Pascal (Borland Turbo Pascal 7.0 con módulo uThreads)
- BETA
- DICHA
- C++ (desde C++20)
- C# (desde la versión 2.0)
- Capilla
- Arrojar
- CLU
- D
- C dinámica
- Erlang
- F#
- Factor
- Guión de GameMonkey
- GDScript (lenguaje de programación de Godot)
- Ir
- Haskell [11] [12]
- Asamblea de Alto Nivel [13]
- Icono
- Yo
- JavaScript (desde 1.7, estandarizado en ECMAScript 6) [14] ECMAScript 2017 también incluye soporte para await .
- Julia [15]
- Kotlin (desde 1.1) [16]
- Limbo
- Luna [17]
- Lúcido
- μC++
- Módulo-2
- Nemerle
- Perl 5 (utilizando el módulo Coro)
- PHP (con HipHop, nativo desde PHP 5.5)
- picolispo
- Prólogo
- Python (desde 2.5, [18] con soporte mejorado desde 3.3 y con sintaxis explícita desde 3.5 [19] )
- Raqueta (lenguaje de programación)
- Raku [20]
- Rubí
- Cuarzo
- Esquema
- Ser
- Simulacro 67 [21]
- Charla informal
- Ardilla
- Python sin pila
- Supercolisionador [22]
- Tcl (desde 8.6)
- escritura urbi
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 2003 [actualizar], muchos de los lenguajes de programación más populares, incluido C y sus derivados, no tienen soporte integrado para corrutinas dentro del lenguaje o sus bibliotecas estándar. Esto se debe, en gran parte, a las limitaciones de la implementación de subrutinas basadas en pila . Una excepción es la biblioteca C++ Boost.Context, parte de las bibliotecas 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 en las que una corrutina sería la implementación natural de un mecanismo, pero no está disponible, la respuesta típica es utilizar 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. Los condicionales 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 estado explícita en forma de una declaración switch grande y compleja o mediante una declaración goto , particularmente un goto calculado . Tales implementaciones se consideran difíciles de entender y mantener, y una motivación para el soporte de corrutinas.
Los subprocesos y, en menor medida, las fibras , son una alternativa a las corrutinas en los entornos de programación convencionales de la actualidad. Los subprocesos proporcionan facilidades para gestionar la interacción cooperativa en tiempo real de fragmentos de código que se ejecutan simultáneamente . Los subprocesos están ampliamente disponibles en entornos que admiten C (y son compatibles de forma nativa en muchos otros lenguajes modernos), son familiares para muchos programadores y, por lo general, están bien implementados, bien documentados y bien respaldados. Sin embargo, como resuelven un problema grande y difícil, incluyen muchas facilidades potentes y complejas y tienen una curva de aprendizaje correspondientemente difícil. Como tal, cuando una corrutina es todo lo que se necesita, usar un subproceso puede ser excesivo.
Una diferencia importante entre subprocesos y corrutinas es que los subprocesos suelen programarse de forma preventiva, mientras que las corrutinas no. Debido a que los subprocesos se pueden reprogramar en cualquier momento y se pueden ejecutar simultáneamente, los programas que utilizan subprocesos deben tener cuidado con el bloqueo . Por el contrario, debido a que las corrutinas solo se pueden reprogramar en puntos específicos del programa y no se ejecutan simultáneamente, los programas que utilizan corrutinas a menudo pueden evitar el bloqueo por completo. Esta propiedad también se cita como un beneficio de la programación asincrónica o basada en eventos .
Dado que las fibras están programadas de forma cooperativa, proporcionan una base ideal para implementar las corrutinas anteriores. [23] Sin embargo, el soporte del sistema para fibras suele ser deficiente en comparación con el de los subprocesos.
do
Para implementar corrutinas de propósito general, se debe obtener una segunda pila de llamadas , que es una característica que no es compatible directamente con el lenguaje C. Una forma confiable (aunque específica de la plataforma) de lograr esto es usar una pequeña cantidad de ensamblaje 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] [ se necesita una fuente no primaria ] En plataformas que proporcionan la llamada al sistema POSIX sigaltstack, se puede obtener una segunda pila de llamadas llamando a una función springboard desde dentro de un controlador de señales [25] [26] para lograr el mismo objetivo en C portable, al costo de cierta complejidad adicional. Las bibliotecas C que cumplen con POSIX o la Especificación Única de Unix (SUSv3) proporcionaron rutinas como getcontext, setcontext, makecontext y swapcontext , pero estas funciones se declararon obsoletas en POSIX 1.2008. [27]
Una vez que se ha obtenido una segunda pila de llamadas con uno de los métodos enumerados anteriormente, las funciones setjmp y longjmp en la biblioteca estándar de C se pueden utilizar para implementar los cambios entre corrutinas. Estas funciones guardan y restauran, respectivamente, el puntero de pila , el contador de programa , los registros guardados por el usuario llamado y cualquier otro estado interno según lo requiera la ABI , de modo que al regresar a una corrutina después de haber dado un rendimiento se restaura todo el estado que se restauraría al regresar de una llamada de función. Las implementaciones minimalistas, que no se apoyan en las funciones setjmp y longjmp, pueden lograr el mismo resultado a través de un pequeño bloque de ensamblaje en línea que intercambia simplemente el puntero de pila y el contador de programa, y bloquea todos los demás registros. Esto puede ser significativamente más rápido, ya que setjmp y longjmp deben almacenar de manera conservadora todos los registros que pueden estar en uso de acuerdo con la ABI, mientras que el método clobber permite al compilador almacenar (al volcar a la pila) solo lo que sabe que realmente está 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 género. 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 de aproximar 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 para 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 pieza de hackery de 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 en todos los rendimientos de la función, no es posible tener múltiples entradas a la función y el control solo puede obtenerse 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 momento 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 corrutinas estándar en versiones recientes. [41]
- concurrencpp - una biblioteca C++20 que proporciona soporte de terceros para corrutinas C++20, en forma de tareas esperables y ejecutores que las ejecutan.
- Boost.Coroutine, creada por Oliver Kowalke, es la biblioteca de corrutinas portable oficial de Boost publicada desde la versión 1.53. La biblioteca se basa en Boost.Context y es compatible con ARM, MIPS, PowerPC, SPARC y X86 en POSIX, Mac OS X y Windows.
- Boost.Coroutine2, también creado por Oliver Kowalke, es una biblioteca de corrutinas portable y modernizada a partir de la versión 1.59 de Boost. Aprovecha las características de C++11, pero elimina la compatibilidad con corrutinas simétricas.
- Mordor - En 2010, Mozy lanzó al mercado el código abierto de una biblioteca C++ que implementa corrutinas, con énfasis en su uso para abstraer E/S asincrónicas en un modelo secuencial más familiar. [42]
- CO2: corrutina sin pila basada en trucos de preprocesador de C++ , que proporciona emulación de espera/rendimiento.
- ScummVM - El proyecto ScummVM implementa una versión liviana de corrutinas sin pila basadas en el artículo de Simon Tatham.
- tonbit::coroutine - Implementación de corrutina asimétrica .h única en C++11 a través de ucontext / fiber
- Las corrutinas llegaron a Clang en mayo de 2017, con la implementación de libc++ en curso. [43]
- Ella por Docker
- oatpp-coroutines: corrutinas sin pila con programación diseñadas para operaciones de E/S de alto nivel de concurrencia. Se utilizan en el experimento de 5 millones de conexiones WebSocket de Oat++. Parte del marco web de Oat++.
DO#
C# 2.0 agregó la funcionalidad de semicorrutina ( generador ) a través del patrón iterador y yieldla palabra clave. [44] [45] C# 5.0 incluye soporte para la sintaxis await . Además:
- El marco REST MindTouch Dream proporciona una implementación de corrutinas basada en el patrón iterador C# 2.0.
- El marco de patrones de pantalla Caliburn (archivado el 19 de enero de 2013 en archive.today ) para WPF utiliza iteradores de C# 2.0 para facilitar la programación de UI, particularmente en escenarios asincrónicos.
- La biblioteca Power Threading (archivada el 24 de marzo de 2010 en Wayback Machine ) de Jeffrey Richter implementa un AsyncEnumerator que proporciona un modelo de programación asincrónica simplificado utilizando corrutinas basadas en iteradores.
- El motor de juego Unity implementa corrutinas.
- El proyecto Servelat Pieces de Yevhen Bobrov proporciona asincronía transparente para los servicios WCF de Silverlight y la capacidad de llamar de forma asincrónica a cualquier método sincrónico. La implementación se basa en el iterador Coroutines de Caliburn y en los bloques iteradores de C#.
- StreamThreads es una biblioteca de co-rutinas de C# liviana y de código abierto basada en métodos de extensión de iteradores. Admite el manejo de errores y valores de retorno.
Clojure
Cloroutine es una biblioteca de terceros que brinda soporte para corrutinas sin pila en Clojure . Se implementa como una macro, que divide estáticamente un bloque de código arbitrario en llamadas var arbitrarias y emite la corrutina como una función con estado.
D
D implementa corrutinas como su clase de biblioteca estándar. Un generador de fibra hace que sea trivial exponer una función de fibra como un rango de entrada , lo que hace que cualquier fibra sea compatible con los algoritmos de rango existentes.
Ir
Go tiene un concepto integrado de " goroutines ", que son procesos ligeros e independientes gestionados por el entorno de ejecución de Go. Se puede iniciar un nuevo goroutine utilizando la palabra clave "go". Cada goroutine tiene una pila de tamaño variable que se puede ampliar según sea necesario. Las goroutines generalmente se comunican utilizando los canales integrados de Go. [46] [47] [48] [49]
Java
Existen varias implementaciones de corrutinas en Java . A pesar de las restricciones impuestas por las abstracciones de Java, la JVM no excluye esta posibilidad. [50] Se utilizan cuatro métodos generales, pero dos rompen la portabilidad del código de bytes entre las JVM compatibles con los estándares.
- JVM modificadas. Es posible crear una JVM parcheada para que admita corrutinas de forma más nativa. Se han creado parches para la JVM Da Vinci. [51]
- Código de bytes modificado. La funcionalidad de corrutina es posible reescribiendo el código de bytes de Java normal, 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 SO o en las bibliotecas C para proporcionar la funcionalidad a la JVM. [ cita requerida ]
- Abstracciones de subprocesos. Las bibliotecas de corrutinas que se implementan mediante subprocesos pueden ser muy pesadas, aunque el rendimiento variará según la implementación de subprocesos de la JVM.
JavaScript
- fibras nodales
- Fibjs: fibjs es un entorno de ejecución de JavaScript creado en el motor de JavaScript V8 de Chrome. fibjs utiliza fibers-switch , estilo de sincronización y un modelo de E/S sin bloqueo para crear sistemas escalables.
- Desde ECMAScript 2015, se proporciona funcionalidad de corrutina sin pila a través de "generadores" y expresiones de rendimiento.
Kotlin
Kotlin implementa corrutinas como parte de una biblioteca propia.
Lua
Lua ha soportado corrutinas asimétricas apilables de primera clase desde la versión 5.0 (2003), [52] en la biblioteca estándar coroutine . [53] [54]
Módulo-2
Modula-2, tal como lo define Wirth, implementa corrutinas como parte de la biblioteca SYSTEM estándar.
El procedimiento NEWPROCESS() rellena un contexto dado un bloque de código y espacio para una pila como parámetros, y el procedimiento TRANSFER() transfiere el control a una corrutina dado el contexto de la corrutina como su parámetro.
Mononucleosis infecciosa
Mono Common Language Runtime tiene soporte para continuaciones, [55] a partir de las cuales se pueden construir corrutinas.
Marco .NET
Durante el desarrollo de .NET Framework 2.0, Microsoft amplió el diseño de las API de hospedaje de Common Language Runtime (CLR) para manejar la programación basada en fibra con miras a su uso en modo de fibra para SQL Server. [56] Antes del lanzamiento, se eliminó la compatibilidad con el gancho de conmutación de tareas ICLRTask::SwitchOut debido a limitaciones de tiempo. [57] En consecuencia, el uso de la API de fibra para cambiar tareas actualmente no es una opción viable en .NET Framework. [ necesita actualización ]
OCaml
OCaml admite corrutinas a través de su Threadmódulo. [58] Estas corrutinas proporcionan concurrencia sin paralelismo y se programan de manera preventiva en un único hilo del sistema operativo. Desde OCaml 5.0, también están disponibles los hilos verdes , proporcionados por diferentes módulos.
Perl
- Coro
Las corrutinas se implementan de forma nativa en todos los backends de Raku . [59]
PHP
- Fibras nativas desde PHP 8.1
- Anphp
- Lana abierta
- Corrutina implementada de una manera que se asemeja a las funciones de Python y algunas de Go , muchos ejemplos muestran su código convertido con el mismo número de líneas y comportamiento.
Pitón
- Python 2.5 implementa un mejor soporte para funcionalidades similares a corrutinas, basadas en generadores extendidos (PEP 342)
- Python 3.3 mejora esta capacidad al admitir la delegación a un subgenerador (PEP 380).
- Python 3.4 presenta un marco de E/S asincrónico integral, tal como se estandarizó 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. [60]
- Evento pequeño
- Vireillo
- evento ge
- Python sin pila
Raqueta
Racket ofrece continuaciones nativas, con una implementación trivial de corrutinas proporcionada en el catálogo oficial de paquetes. Implementación de S. De Gabrielle
Rubí
- Ruby 1.9 admite corrutinas de forma nativa que se implementan como fibras, que son semicorrutinas. [61]
- Una implementación de Marc De Scheemaecker
- Ruby 2.5 y versiones superiores admiten corrutinas de forma nativa que se implementan como fibras.
- Una implementación de Thomas W Branson
Esquema
Dado que Scheme proporciona soporte completo para continuaciones, la implementación de corrutinas es casi trivial y solo requiere que se mantenga una cola de continuaciones.
Charla informal
Dado que, en la mayoría de los entornos Smalltalk , la pila de ejecución es un ciudadano de primera clase, las corrutinas se pueden implementar sin necesidad de biblioteca adicional o soporte de VM.
Lenguaje de comandos de herramientas (Tcl)
Desde la versión 8.6, el lenguaje de comandos de herramientas admite corrutinas en el lenguaje principal. [62]
Vala
Vala implementa soporte nativo para corrutinas. Están diseñadas para usarse con un bucle principal de Gtk, pero se pueden usar solas si se tiene cuidado de garantizar que nunca sea necesario llamar a la devolución de llamada final antes de realizar, al menos, una operación de rendimiento.
Lenguajes ensambladores
Los lenguajes ensambladores dependientes de la máquina a menudo proporcionan 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 efectúa mediante la instrucción "JSR PC,@(SP)+", que salta a la dirección extraída de la pila y empuja la dirección de instrucción actual ( es decir , la de la siguiente ) a 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++]"; note el "++", ya que se extraen 2 bytes (de dirección) de la pila. Esta instrucción se usa mucho en el 'monitor' (estándar) Assist 09.
Véase también
- Asíncrono/espera
- Pipeline , un tipo de corrutina utilizada para la comunicación entre programas [63]
- Protothreads , una implementación de subprocesos livianos sin pila que utiliza un mecanismo similar a una corrutina
Referencias
- ^ "¿Cómo diablos funciona async/await en Python 3.5?". Canadiense alto y sarcástico . 2016-02-11 . Consultado el 2023-01-10 .
- ^ 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-1. Archivado (PDF) del original el 21 de octubre de 2019.
- ^ Conway, Melvin E. (julio de 1963). "Diseño de un compilador de diagrama de transición separable" (PDF) . Comunicaciones de la ACM . 6 (7). ACM: 396–408. doi :10.1145/366663.366704. ISSN 0001-0782. S2CID 10559786 – vía ACM Digital Library.
- ^ Marlin, Christopher (1980). Corrutinas: una metodología de programación, un diseño de lenguaje y una implementación . Springer. ISBN 3-540-10256-6.
- ^ Ana Lucia de Moura; Roberto Ierusalimschy (2009). "Revisitando corrutinas". ACM Transactions on Programming Languages and Systems . 31 (2): 1–31. CiteSeerX 10.1.1.58.4017 . doi :10.1145/1462166.1462167. S2CID 9918449.
- ^ ab 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.
- ^ 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 desde el original el 17 de enero de 1999.
6. La simetría es un concepto que reduce la complejidad (las co-rutinas incluyen subrutinas); búsquelo en todas partes
- ^ Anthony Ralston (2000). Enciclopedia de informática. Nature Pub. Group. ISBN 978-1-56159-248-7. Recuperado el 11 de mayo de 2013 .
- ^ Ver, por ejemplo, la Referencia del lenguaje Python
"https://docs.python.org/reference/expressions.html#yieldexpr 5.2.10. Expresiones de rendimiento]":
"Todo esto hace que las funciones generadoras sean bastante similares a las corrutinas; rinden 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 que cede; el control siempre se transfiere al llamador del generador". - ^ Mertz, David (1 de julio de 2002). «Máquinas de estados basadas en generadores». Charming Python . IBM developerWorks. Archivado desde el original el 28 de febrero de 2009. Consultado el 2 de febrero de 2011 .
- ^ "Corrutina: Corrutinas de tipos seguros que utilizan tipos de sesión ligeros".
- ^ "Co-rutinas en Haskell".
- ^ "El módulo Coroutines (coroutines.hhf)". Manual de la biblioteca estándar de HLA .
- ^ "Novedades en JavaScript 1.7". Archivado desde el original el 8 de marzo de 2009. Consultado el 18 de junio de 2018 .
- ^ "Manual de Julia - Flujo de control - Tareas (también conocidas como corrutinas)".
- ^ "Novedades en Kotlin 1.1".
- ^ "Manual de referencia de Lua 5.2". www.lua.org .
- ^ "Tutorial de Python async/await". Stack Abuse . 17 de diciembre de 2015.
- ^ "8. Declaraciones compuestas — Documentación de Python 3.8.0". docs.python.org .
- ^ "Recopilación y/o Corrutinas". 19-12-2012.
- ^ 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.
- ^ McCartney, J. "Replanteando el lenguaje de programación de música por ordenador: SuperCollider". Computer Music Journal, 26(4):61-68. MIT Press, 2002.
- ^ Implementación de corrutinas para .NET mediante la encapsulación de la API de fibra no administrada Archivado el 7 de septiembre de 2008 en Wayback Machine , Ajai Shankar, MSDN Magazine
- ^ abc "Corrutinas en C – brainwagon". 5 de marzo de 2005.
- ^ Ralf S. Engelschall (18–23 de junio de 2000). Multithreading portátil: el truco de la pila de señales para la creación de subprocesos en el espacio de usuario (PS) . Conferencia técnica anual de USENIX. San Diego, EE. UU.
- ^ desde "libco". code.byuu.org .[ enlace muerto permanente ]
- ^ "getcontext(3) - Página del manual de Linux". man7.org .
- ^ http://swtch.com/libtask/ - Biblioteca de corrutinas libtask de Russ Cox para FreeBSD, Linux, Mac OS X y SunOS
- ^ Biblioteca de corrutinas portátil: biblioteca C que utiliza las funciones POSIX/SUSv3
- ^ http://www.goron.de/~froese/coro/ Archivado el 10 de enero de 2006 en Wayback Machine - Biblioteca coro de Edgar Toernig para x86, Linux y FreeBSD
- ^ https://github.com/halayli/lthread - lthread es una biblioteca de corrutinas multinúcleo/multihilo escrita en C
- ^ "libcoroutine: una implementación de corrutina portátil". Archivado desde el original el 12 de noviembre de 2019. Consultado el 6 de septiembre de 2013 .para FreeBSD, Linux, OS X PPC y x86, SunOS, Symbian y otros
- ^ "libconcurrency - Una biblioteca de concurrencia escalable para C".Una biblioteca C sencilla para corrutinas portátiles de cambio de pila
- ^ "libcoro: biblioteca C que implementa corrutinas (multitarea cooperativa) de manera portable".utilizado como base para el módulo perl Coro.
- ^ "RIBS (Infraestructura robusta para sistemas backend) versión 2: aolarchive/ribs2". 13 de agosto de 2019 – vía GitHub.
- ^ "libdill". libdill.org . Archivado desde el original el 2019-12-02 . Consultado el 2019-10-21 .
- ^ "Una biblioteca de corrutinas asimétricas de C increíblemente rápida y liviana 💎 ⛅🚀⛅🌞: hnes/libaco". 21 de octubre de 2019 – vía GitHub.
- ^ por Simon Tatham (2000). "Corrutinas en C".
- ^ "Implementación de corrutinas sin pila en C y C++: jsseldenthuis/coroutine". 18 de marzo de 2019 – vía GitHub.
- ^ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4680.pdf - Especificación técnica para corrutinas
- ^ https://en.cppreference.com/w/cpp/compiler_support#cpp20 - Compatibilidad actual del compilador con corrutinas estándar
- ^ http://mozy.com/blog/announcements/open-source-and-mozy-the-debut-of-mozy-code/ - Código abierto y Mozy: el debut de Mozy Code
- ^ https://twitter.com/eric01/status/867473461836263424 - EricWF: ¡Las corrutinas ya están en Clang Trunk! Estamos trabajando en la implementación de Libc++.
- ^ Wagner, Bill (11 de noviembre de 2021). "Iteradores". Documentación de C# . Microsoft – vía Microsoft Learn.
- ^ Wagner, Bill (13 de febrero de 2023). "La historia de C#". Documentación de C# . Microsoft . Versión 2.0 de C#: a través de Microsoft Learn.
- ^ "Goroutines - Go eficaz". go.dev . Consultado el 28 de noviembre de 2022 .
- ^ "Declaraciones Go - La especificación Go". go.dev . Consultado el 28 de noviembre de 2022 .
- ^ "Goroutines - Un recorrido por Go". go.dev . Consultado el 28 de noviembre de 2022 .
- ^ "Preguntas frecuentes (FAQ) - El lenguaje de programación Go". go.dev .
- ^ Lukas Stadler (2009). "Continuaciones de JVM" (PDF) . Cumbre del lenguaje JVM.
- ^ Remi Forax (19 de noviembre de 2009). "Dios mío: la JVM tiene corrutinas, continuidad, fibra, etc." Archivado desde el original el 19 de marzo de 2015.
- ^ "Historial de versiones de Lua". Lua.org .
- ^ de Moura, Ana Lucía; Rodríguez, Noemí; Jerusalén, Roberto. "Corrutinas en Lua" (PDF) . Lua.org . Consultado el 24 de abril de 2023 .
- ^ de Moura, Ana Lucía; Rodríguez, Noemí; Jerusalén, Roberto (2004). "Corrutinas en Lua". Revista de Informática Universal . 10 (7): 901--924.
- ^ http://www.mono-project.com/Continuations Continuaciones Mono
- ^ http://blogs.msdn.com/cbrumme/archive/2004/02/21/77595.aspx, Chris Brumme, WebLog de cbrumme
- ^ kexugit (15 de septiembre de 2005). "El modo de fibra ha desaparecido..." docs.microsoft.com . Consultado el 8 de junio de 2021 .
- ^ "La biblioteca de hilos".
- ^ "RFC #31".
- ^ "Novedades de Python 3.7" . Consultado el 10 de septiembre de 2021 .
- ^ "semi-coroutines". Archivado desde el original el 24 de octubre de 2007.
- ^ "Página del manual de corrutinas - Comandos integrados de Tcl". Tcl.tk . Consultado el 27 de junio de 2016 .
- ^ Ritchie, Dennis M. (1980). "La evolución del sistema de tiempo compartido Unix". Diseño de lenguajes y metodología de programación. Apuntes de clase en informática. Vol. 79. págs. 25-35. doi :10.1007/3-540-09745-7_2. ISBN 978-3-540-09745-7. S2CID 571269. Archivado desde el original el 8 de abril de 2015. Consultado el 26 de enero de 2011 .
Lectura adicional
- Ana Lucia de Moura; Roberto Ierusalimschy (2004). "Revisitando corrutinas". ACM Transactions on Programming Languages and Systems . 31 (2): 1–31. CiteSeerX 10.1.1.58.4017 . doi :10.1145/1462166.1462167. S2CID 9918449.
Enlaces externos
- Introducción completa a las corrutinas orientada al lenguaje C de Simon Tatham
- Página de corrutinas de Softpanorama: contiene enlaces completos a corrutinas de ensamblador