Las corrutinas son componentes de programas de computadora que generalizan subrutinas para multitarea no preventiva , al permitir que la ejecución se suspenda y reanude. Las corrutinas son adecuadas para implementar componentes de programas familiares, como tareas cooperativas , excepciones , bucles de eventos , iteradores , listas infinitas y canalizaciones .
Según Donald Knuth , Melvin Conway acuñó el término coroutine en 1958 cuando lo aplicó a la construcción de un programa de montaje . [1] La primera explicación publicada de la corrutina apareció más tarde, en 1963. [2]
Comparación con subrutinas
Las subrutinas son casos especiales de corrutinas. [3] Cuando se invocan subrutinas, la ejecución comienza al principio y, una vez que una subrutina sale, finaliza; una instancia de una subrutina solo regresa una vez y no mantiene el estado entre invocaciones. Por el contrario, las corrutinas pueden salir llamando a otras corrutinas, que luego pueden volver 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. [3] Por lo tanto, una instancia de corrutina mantiene el estado y varía entre invocaciones; puede haber varias instancias de una corrutina determinada a la vez. La diferencia entre llamar a otra corrutina por medio de "ceder" a ella y simplemente llamar a otra rutina (que luego, también, volvería al punto original), es que la relación entre dos corrutinas que ceden entre sí no es la del llamador. -callee, pero en cambio simétrico.
Cualquier subrutina se puede traducir a una corrutina que no llama rendimiento . [4]
Aquí hay un ejemplo simple de cómo las corrutinas pueden ser útiles. Suponga que tiene una relación consumidor-productor en la que una rutina crea elementos y los agrega a una cola y otra los quita de la cola y los usa. Por razones de eficiencia, desea agregar y eliminar varios elementos a la vez. El código podría verse así:
var q: = nueva colacorutina produce bucle mientras q no está lleno crear algunos elementos nuevos agregue los elementos a q ceder para consumircoroutine consume bucle mientras q no está vacío eliminar algunos elementos de q usar los artículos rendimiento para producirllamar a producir
Luego, la cola se llena o se vacía completamente antes de ceder el control a la otra corrutina usando el comando de rendimiento . Las demás llamadas de corrutinas comienzan justo después del rendimiento , en el bucle externo de corrutinas.
Aunque este ejemplo se usa a menudo como una introducción al subproceso múltiple , no se necesitan dos subprocesos para esto: la declaración de rendimiento se puede implementar mediante un salto directamente de una rutina a la otra.
Comparación con hilos
Las corrutinas son muy similares a los hilos . Sin embargo, las corrutinas son multitarea cooperativamente , mientras que los subprocesos suelen ser multitarea preventivamente . Esto significa que las corrutinas proporcionan simultaneidad pero no paralelismo . Las ventajas de las corrutinas sobre los subprocesos son que pueden usarse en un contexto de tiempo real duro (el cambio entre corrutinas no necesita involucrar ninguna llamada al sistema ni ninguna llamada de bloqueo ), no hay necesidad de primitivas de sincronización como mutex , semáforos, etc. para proteger las secciones críticas , y no hay necesidad de soporte del sistema operativo.
Es posible implementar corrutinas usando subprocesos programados de manera preventiva, de una manera que será transparente para el código de llamada, pero se perderán algunas de las ventajas (particularmente la idoneidad para la operación en tiempo real duro y la relativa economía de cambiar entre ellas).
Comparación con generadores
Los generadores , también conocidos como semicorutinas, [5] son un subconjunto de 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 ceder, mientras que los generadores no pueden, en lugar de transferir el control al llamador del generador. . [6] Es decir, dado que los generadores se utilizan principalmente para simplificar la escritura de iteradores , la yield
declaración en un generador no especifica una corrutina a la que saltar, sino que devuelve un valor a una rutina principal.
Sin embargo, todavía es posible implementar corrutinas en la parte superior de una instalación de generador, con la ayuda de una rutina de despachador de nivel superior (un trampolín , esencialmente) que pasa el control explícitamente a los generadores secundarios identificados por tokens devueltos desde los generadores:
var q: = nueva colagenerador produce bucle mientras q no está lleno crear algunos elementos nuevos agregue los elementos a q rendimiento consumirgenerador consume bucle mientras q no está vacío eliminar algunos elementos de q usar los artículos rendimiento de productosdespachador de subrutinas var d: = nuevo diccionario ( generador → iterador ) d [producir]: = empezar a producir d [consumir]: = iniciar consumir var actual: = producir corriente de llamada de bucle actual: = siguiente d [actual]despachador de llamadas
Varias implementaciones de corrutinas para lenguajes con soporte de generador pero sin corrutinas nativas (por ejemplo, Python [7] antes de 2.5) usan este o un modelo similar.
Comparación con recursividad mutua
El uso de corrutinas para máquinas de estado o concurrencia es similar al uso de recursividad mutua con llamadas de cola , ya que en ambos casos el control cambia a uno 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 reiniciarse desde el principio, pueden mantener el estado, tanto las variables (como en un cierre) como el punto de ejecución, y los rendimientos no se limitan a estar en la posición final; las subrutinas mutuamente recursivas deben utilizar 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 la llamada de cola ), mientras que pasar el control entre corrutinas usa los contextos existentes y puede implementarse simplemente mediante un salto.
Usos comunes
Las corrutinas son útiles para implementar lo siguiente:
- Máquinas de estado 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 se puede implementar mediante recursividad mutua con llamadas de cola .
- Modelo actor de concurrencia, por ejemplo en videojuegos . Cada actor tiene sus propios procedimientos (esto nuevamente separa lógicamente el código), pero ceden voluntariamente el control al programador central, que los ejecuta secuencialmente (esta es una forma de multitarea cooperativa ).
- Generadores , y estos son útiles para flujos , en particular de entrada / salida, y para el recorrido genérico de estructuras de datos.
- Comunicar procesos secuenciales donde cada subproceso es una corrutina. Las entradas / salidas de canal y las operaciones de bloqueo producen corrutinas y un programador las desbloquea en eventos de finalización. Alternativamente, cada subproceso puede ser el padre del que lo sigue en la canalización de datos (o que lo precede, en cuyo caso el patrón se puede expresar como generadores anidados).
- Comunicación inversa, comúnmente utilizada en software matemático, donde un procedimiento como un solucionador, evaluador integral, ... necesita el proceso de uso para hacer un cálculo, como evaluar una ecuación o integrando.
Lenguajes de programación con 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 . Los primeros ejemplos incluyen Simula , [8] Smalltalk y Modula-2 . Los ejemplos más recientes son Ruby , Lua , Julia y Go .
- Aikido
- AngelScript
- Bailarina
- BCPL
- Pascal (Borland Turbo Pascal 7.0 con módulo uThreads)
- BETA
- FELICIDAD
- C ++ (desde C ++ 20)
- C # (desde 2.0)
- Capilla
- Arrojar
- CLU
- D
- Dinámico C
- Erlang
- F#
- Factor
- Guión de GameMonkey
- GDScript (lenguaje de programación de Godot)
- Ir
- Haskell [9] [10]
- Asamblea de alto nivel [11]
- Icono
- Io
- JavaScript (desde 1.7, estandarizado en ECMAScript 6) [12] ECMAScript 2017 también incluye soporte en espera .
- Julia [13]
- Kotlin (desde 1.1) [14]
- Limbo
- Lua [15]
- Lúcido
- µC ++
- Modula-2
- Nemerle
- Perl 5 (usando el módulo Coro )
- PHP (con HipHop , nativo desde PHP 5.5)
- Picolisp
- Prólogo
- Python (desde 2.5, [16] con soporte mejorado desde 3.3 y con sintaxis explícita desde 3.5 [17] )
- Raku [18]
- Rubí
- Óxido (desde 1.39)
- Sather
- Esquema
- Uno mismo
- Simula 67
- Charla
- Ardilla
- Python sin pila
- SuperCollider [19]
- Tcl (desde 8.6)
- urbiscript
Dado que las continuaciones se pueden utilizar 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 directo 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 pilas . 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 construir 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 banderas booleanas) para mantener un estado interno entre llamadas, y para 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 de conmutación grande y compleja o mediante una declaración goto , en particular un goto calculado . Tales implementaciones se consideran difíciles de entender y mantener, y una motivación para el soporte de rutina.
Los hilos y, en menor medida , las fibras , son una alternativa a las corrutinas en los entornos de programación convencionales actuales. Los subprocesos proporcionan facilidades para gestionar la interacción cooperativa en tiempo real de la ejecución simultánea de fragmentos de código. Los subprocesos están ampliamente disponibles en entornos que admiten C (y se admiten 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 instalaciones poderosas y complejas y tienen una curva de aprendizaje correspondientemente difícil. Como tal, cuando una corrutina es todo lo que se necesita, usar un hilo puede ser excesivo.
Una diferencia importante entre los hilos y las corrutinas es que los hilos normalmente se programan de forma preventiva, mientras que las corrutinas no. Debido a que los subprocesos se pueden reprogramar en cualquier instante y se pueden ejecutar al mismo tiempo, 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 al mismo tiempo, los programas que usan corrutinas a menudo pueden evitar el bloqueo por completo. Esta propiedad también se cita como un beneficio de la programación asíncrona o impulsada por eventos.
Dado que las fibras se programan de manera cooperativa, proporcionan una base ideal para implementar las corrutinas anteriores. [20] Sin embargo, el soporte del sistema para las fibras a menudo falta en comparación con el de los hilos.
Implementaciones para C
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 la 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 . [21] En plataformas que proporcionan la llamada al sistema POSIX sigaltstack , se puede obtener una segunda pila de llamadas llamando a una función de trampolín desde dentro de un manejador de señales [22] [23] para lograr el mismo objetivo en el portátil C, a costa de algunos complejidad extra. Las bibliotecas C que cumplían con POSIX o la Especificación Única de Unix (SUSv3) proporcionaban rutinas como getcontext, setcontext, makecontext y swapcontext , pero estas funciones se declararon obsoletas en POSIX 1.2008. [24]
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 C estándar se pueden usar para implementar los cambios entre corrutinas. Estas funciones guardar y restaurar, respectivamente, el puntero de pila , contador de programa , destinatario de la llamada-guardado registros , y cualquier otro estado interno como lo requiere la ABI , de tal manera que volver a una co-rutina después de tener restauraciones cedido todo el estado que sería restaurado a su regreso desde una llamada de función. Las implementaciones minimalistas, que no se complementan con 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 la pila y el contador del 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 derramarse en la pila) solo lo que sabe que está realmente en uso.
Debido a la falta de soporte de lenguaje directo, muchos autores han escrito sus propias bibliotecas para corrutinas que ocultan los detalles anteriores. La biblioteca libtask de Russ Cox [25] es un buen ejemplo de este género. Utiliza las funciones de contexto si las proporciona la biblioteca C nativa; de lo contrario, proporciona sus propias implementaciones para ARM, PowerPC, Sparc y x86. Otras implementaciones notables incluyen libpcl, [26] coro, [27] lthread, [28] libCoroutine, [29] libconcurrency, [30] libcoro, [31] ribs2, [32] libdill., [33] libaco, [34] y libco. [23]
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 , [35] basada en el dispositivo de Duff , es un ejemplo notable del género y es la base para Protothreads e implementaciones similares. [36] Además de las objeciones de Duff, [21] 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 hacker en C jamás vista en código de producción serio". [35] 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 los rendimientos de la función, no es posible tener múltiples entradas a la función y el control solo puede ceder a partir de la rutina de nivel superior. [21]
Implementaciones para 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. [37] La implementación de este estándar está en curso, y los compiladores G ++ y MSVC actualmente soportan completamente las corrutinas estándar en versiones recientes. [38]
- Boost.Coroutine : creado por Oliver Kowalke, es la biblioteca de coroutine portátil lanzada oficialmente de boost 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 coroutine portátil modernizada desde la versión de boost 1.59. Aprovecha las características de C ++ 11, pero elimina el soporte para corrutinas simétricas.
- Mordor : en 2010, Mozy abrió una biblioteca C ++ que implementaba corrutinas, con énfasis en su uso para abstraer la E / S asíncrona en un modelo secuencial más familiar. [39]
- CO2 : corrutina sin pila basada en trucos del preprocesador de C ++ , que proporciona emulación de espera / rendimiento.
- ScummVM : el proyecto ScummVM implementa una versión liviana de corrutinas sin pila basada en el artículo de Simon Tatham .
- tonbit :: coroutine - C ++ 11 implementación de una sola corrutina asimétrica .h a través de ucontext / fiber
- Coroutines aterrizó en Clang en mayo de 2017, con la implementación de libc ++ en curso. [40]
- elle de Docker
- oatpp-coroutines : corrutinas sin pila con programación diseñadas para operaciones de E / S de alto nivel de concurrencia. Utilizado en el experimento de 5 millones de conexiones WebSocket de Oat ++. Parte del marco web Oat ++ .
Implementaciones para C #
- MindTouch Dream : el marco MindTouch Dream REST proporciona una implementación de corrutinas basadas en el patrón de iterador C # 2.0
- Caliburn : el marco de trabajo de patrones de pantalla de Caliburn para WPF utiliza iteradores de C # 2.0 para facilitar la programación de la interfaz de usuario, especialmente en escenarios asincrónicos.
- Biblioteca Power Threading: la biblioteca Power Threading de Jeffrey Richter implementa un AsyncEnumerator que proporciona un modelo de programación asincrónico simplificado utilizando corrutinas basadas en iteradores.
- El motor de juego de Unity implementa corrutinas.
- Servelat Pieces : 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 síncrono. La implementación se basa en el iterador Coroutines de Caliburn y en los bloques iteradores de C #.
- [10] - El .NET 2.0+ Framework ahora proporciona funcionalidad de semicorutina ( generador ) a través del patrón de iterador y la palabra clave de rendimiento.
C # 5.0 incluye soporte de sintaxis en espera .
Implementaciones para Clojure
Cloroutine es una biblioteca de terceros que brinda soporte para corrutinas sin pila en Clojure . Se implementa como una macro, dividiendo estáticamente un bloque de código arbitrario en llamadas var arbitrarias y emitiendo la corrutina como una función con estado.
Implementaciones para D
D implementa corrutinas como su clase de biblioteca estándar El generador de fibra A hace que sea trivial exponer una función de fibra como un rango de entrada , haciendo que cualquier fibra sea compatible con los algoritmos de rango existentes.
Implementaciones para Java
Hay varias implementaciones para corrutinas en Java . A pesar de las limitaciones impuestas por las abstracciones de Java, la JVM no excluye la posibilidad. [41] Se utilizan cuatro métodos generales, pero dos rompen la portabilidad del código de bytes entre las JVM que cumplen con los estándares.
- JVM modificadas. Es posible construir una JVM parcheada para soportar corrutinas de forma más nativa. Se han creado parches para Da Vinci JVM . [42]
- Código de bytes modificado. La funcionalidad de corrutina es posible reescribiendo el código de bytes 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 las bibliotecas de OS o C para proporcionar la funcionalidad a la JVM. [ cita requerida ]
- Hilo de abstracciones. Las bibliotecas de rutina que se implementan mediante subprocesos pueden ser pesadas, aunque el rendimiento variará según la implementación de subprocesos de la JVM.
Implementaciones en JavaScript
- fibras de nodo
- Fibjs : fibjs es un tiempo de ejecución de JavaScript construido en el motor de JavaScript V8 de Chrome. fibjs utiliza un modelo de E / S sin bloqueo, estilo de sincronización y conmutación de fibras para construir sistemas escalables.
- Desde ECMAScript 2015 , se proporciona la funcionalidad de corrutina sin pila a través de "generadores" y expresiones de rendimiento.
Implementaciones para Kotlin
Kotlin implementa corrutinas como parte de una biblioteca propia .
Implementaciones para Modula-2
Modula-2 , tal como lo define Wirth, implementa corrutinas como parte de la biblioteca SYSTEM estándar.
El procedimiento NEWPROCESS () llena 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 parámetro.
Implementación en Mono
El Mono Common Language Runtime tiene soporte para continuaciones, [43] a partir del cual se pueden construir corrutinas.
Implementación en .NET Framework como fibras
Durante el desarrollo de .NET Framework 2.0, Microsoft extendió el diseño de las API de hospedaje Common Language Runtime (CLR) para manejar la programación basada en fibra con miras a su uso en modo de fibra para el servidor SQL. [44] Antes del lanzamiento, se eliminó el soporte para el gancho de conmutación de tareas ICLRTask :: SwitchOut debido a limitaciones de tiempo. [45] En consecuencia, el uso de la API de fibra para cambiar tareas no es actualmente una opción viable en .NET Framework.
Implementaciones para Perl
- Coro
Las corrutinas se implementan de forma nativa en todos los backends de Raku . [46]
Implementaciones para PHP
- Amphp
- Coroutine implementado de una manera que se asemeja a las funciones de Python , y algunos Go , muchos ejemplos que muestran su código convertido con el mismo número de líneas y comportamiento.
Implementaciones para Python
- Python 2.5 implementa un mejor soporte para la funcionalidad similar a una corrutina, basada 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 de trabajo de E / S asíncrono integral como está estandarizado en PEP 3156 , que incluye corrutinas que aprovechan la delegación del subgenerador
- Python 3.5 introduce soporte explícito para corrutinas con sintaxis asíncrona / en espera ( PEP 0492 ).
- Desde Python 3.7 async / await se convirtió en palabras clave reservadas [11] .
- Eventlet
- Vireillo
- gevent
- pitón sin pila
- Abandonado
- Metralla (último lanzamiento 2015)
- Kamaelia (última versión 2010)
- cogen (último lanzamiento 2009)
- multitarea (última versión 2007)
- quiral
Implementaciones para Ruby
- Ruby 1.9 admite corutinas de forma nativa que se implementan como fibras , que son semicorutinas. [47]
- Una implementación de Marc De Scheemaecker
- Ruby 2.5 y superior admite corrutinas de forma nativa que se implementan como fibras
- Una implementación de Thomas W Branson
Implementaciones para Rust
Rust admite corrutinas desde la versión 1.39. [48] Hay dos bibliotecas populares que proporcionan tiempos de ejecución asincrónicos: tokio y async-std
Implementaciones para Scala
Scala Coroutines [49] es una implementación de corrutinas para Scala . Esta implementación es una extensión a nivel de biblioteca que se basa en el sistema de macros Scala para transformar estáticamente secciones del programa en objetos de rutina. Como tal, esta implementación no requiere modificaciones en la JVM, por lo que es totalmente portátil entre diferentes JVM y funciona con backends alternativos de Scala, como Scala.js , que se compila en JavaScript. [50]
Scala Coroutines se basa en la coroutine
macro que transforma un bloque de código normal en una definición de corrutina. Esta definición de corrutina se puede invocar con la call
operación, que crea una instancia de un marco de corrutina. Un marco de corrutina se puede reanudar con el resume
método, que reanuda la ejecución del cuerpo de la corrutina, hasta llegar a una yieldval
palabra clave, que suspende el marco de corrutina. Scala Coroutines también expone un snapshot
método que duplica efectivamente la corrutina. [51] En ECOOP 2018 aparecieron descripciones detalladas de las corrutinas Scala con instantáneas , junto con su modelo formal .
Implementaciones para Scheme
Dado que Scheme proporciona soporte completo para continuaciones, implementar corrutinas es casi trivial, y solo requiere que se mantenga una cola de continuaciones.
Implementaciones para Smalltalk
Dado que, en la mayoría de los entornos de Smalltalk , la pila de ejecución es un ciudadano de primera clase, las corrutinas se pueden implementar sin biblioteca adicional o soporte de VM.
Implementaciones para Swift
- SwiftCoroutine : biblioteca de corrutinas Swift para iOS, macOS y Linux.
Implementación para el lenguaje de comandos de herramientas (Tcl)
Desde la versión 8.6, Tool Command Language admite corrutinas en el lenguaje principal. [52]
Implementaciones para Vala
Vala implementa soporte nativo para corrutinas. Están diseñados para usarse con un bucle principal Gtk, pero se pueden usar solos si se tiene cuidado de garantizar que nunca se tenga que llamar a la devolución de llamada final antes de realizar, al menos, un rendimiento.
Implementaciones en 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 miniordenadores PDP-11 , el cambio de rutina "clásico" se efectúa mediante la instrucción "JSR PC, @ (SP) +", que salta a la dirección extraída de la stack y empuja la dirección de instrucción actual ( es decir, la de la siguiente ) a la pila. En VAXen (en Macro-32 ), la instrucción comparable es "JSB @ (SP) +". Incluso en un Motorola 6809 existe la instrucción "JSR [, S ++]"; tenga en cuenta el "++", ya que 2 bytes (de dirección) se extraen de la pila. Esta instrucción se utiliza mucho en el (estándar) 'Monitor' Assist 09.
Ver también
- Asíncrono / espera
- Generador (programación de computadoras)
- Pipeline (Unix) , una especie de corrutina utilizada para comunicarse entre programas [53]
- Protothreads , una implementación de subprocesos livianos sin pilas que utiliza un mecanismo similar a una corrutina
Referencias
- ^ Knuth, Donald Ervin (1997). Algoritmos fundamentales (PDF) . El arte de la programación informática. 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) desde el 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 . ACM. 6 (7): 396–408. doi : 10.1145 / 366663.366704 . ISSN 0001-0782 . S2CID 10559786 : a través de la biblioteca digital ACM.
- ^ a b Knuth, Donald Ervin (1997). Algoritmos fundamentales . El arte de la programación informática. 1 (3ª ed.). Addison-Wesley. Sección 1.4.2: Corutinas, págs. 193–200. ISBN 978-0-201-89683-1.
- ^ Perlis, Alan J. (septiembre de 1982). "Epigramas sobre programación" . Avisos ACM SIGPLAN . 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 sub-rutinas); búscalo en todas partes
- ^ Anthony Ralston (2000). Enciclopedia de informática . Nature Pub. Grupo. ISBN 978-1-56159-248-7. Consultado el 11 de mayo de 2013 .
- ^ Consulte, 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 del generador sean bastante similares a las corrutinas; producen múltiples veces, tienen más de un punto de entrada y su ejecución puede suspenderse. La única diferencia es que una función de generador no puede controlar dónde debe continuar la ejecución después de ceder; el control siempre se transfiere al llamador del generador ". - ^ Mertz, David (1 de julio de 2002). "Máquinas de estado basadas en generadores" . Pitón encantador . IBM developerWorks. Archivado desde el original el 28 de febrero de 2009 . Consultado el 2 de febrero de 2011 .
- ^ Dahl, O.-J. y Hoare, CAR (ed.) (1972). "Estructuras jerárquicas del programa". Programación estructurada . Londres, Reino Unido: Academic Press. págs. 175–220. ISBN 978-0122005503.CS1 maint: varios nombres: lista de autores ( enlace ) CS1 maint: texto adicional: lista de autores ( enlace )
- ^ "Corutina: corrutinas de tipo seguro utilizando tipos de sesión ligeros" .
- ^ "Co-rutinas en Haskell" .
- ^ "El módulo de corrutinas (coroutines.hhf)" . Manual de la biblioteca estándar de HLA .
- ^ "Nuevo en JavaScript 1.7" .
- ^ "Manual de Julia - Flujo de control - Tareas (también conocido como Coroutines)" .
- ^ "Novedades de Kotlin 1.1" .
- ^ "Manual de referencia de Lua 5.2" . www.lua.org .
- ^ "Tutorial de Python async / await" . Abuso de pila . 17 de diciembre de 2015.
- ^ "8. Declaraciones compuestas - Documentación de Python 3.8.0" . docs.python.org .
- ^ "Reunir y / o Coroutines" . 2012-12-19.
- ^ McCartney, J. "Repensar el lenguaje de programación de música de computadora: SuperCollider" . Computer Music Journal, 26 (4): 61-68. Prensa del MIT, 2002.
- ^ Implementación de corrutinas para .NET envolviendo la API de fibra no administrada Archivado el 7 de septiembre de 2008 en Wayback Machine , Ajai Shankar, MSDN Magazine
- ^ a b c "Corutinas en C - brainwagon" .
- ^ https://www.gnu.org/software/pth/rse-pmt.ps
- ^ a b "libco" . code.byuu.org .
- ^ "getcontext (3) - página de manual de Linux" . man7.org .
- ^ [1] - Biblioteca de rutinas libtask de Russ Cox para FreeBSD, Linux, Mac OS X y SunOS
- ^ Biblioteca de Coroutine Portátil - Biblioteca C que usa instalaciones POSIX / SUSv3
- ^ [2] Archivado el10 de enero de 2006en Wayback Machine : la biblioteca coro de Edgar Toernig para x86, Linux y FreeBSD
- ^ [3] - lthread es una biblioteca de corrutinas multinúcleo / multiproceso escrita en C
- ^ "libcoroutine: una implementación de coroutine portátil" . para FreeBSD, Linux, OS X PPC y x86, SunOS, Symbian y otros
- ^ "libconcurrency: una biblioteca de concurrencia escalable para C" . una biblioteca C simple para corrutinas portátiles de conmutación de pila
- ^ "libcoro: C-biblioteca que implementa corrutinas (multitarea cooperativa) de forma portátil" . utilizado como base para el módulo de Coro perl.
- ^ "RIBS (infraestructura robusta para sistemas backend) versión 2: aolarchive / ribs2" . 13 de agosto de 2019 - a través de GitHub.
- ^ "libdill" . libdill.org .
- ^ "Una biblioteca de corrutinas asimétricas C ultrarrápida y liviana 💎 ⛅🚀⛅🌞: hnes / libaco" . 21 de octubre de 2019 - a través de GitHub.
- ^ a b Simon Tatham (2000). "Corutinas en C" .
- ^ "Implementación de corrutinas sin pila en C y C ++: jsseldenthuis / coroutine" . 18 de marzo de 2019 - a través de GitHub.
- ^ [4] - Especificación técnica para corrutinas
- ^ [5] - Soporte actual del compilador para corrutinas estándar
- ^ [6] - Código abierto y Mozy: el debut de Mozy Code
- ^ [7] - EricWF: ¡Coroutines ahora están en Clang Trunk! Trabajando en la implementación de Libc ++ ahora.
- ^ Lukas Stadler (2009). "Continuaciones de JVM" (PDF) . Cumbre de idiomas de JVM.
- ^ Remi Forax (19 de noviembre de 2009). "Santa mierda: JVM tiene co-rutina / continuación / fibra, etc." . Archivado desde el original el 19 de marzo de 2015.
- ^ [8] Continuaciones mono
- ^ [9] , Chris Brumme, WebLog de cbrumme
- ^ kexugit. "El modo de fibra se ha ido ..." docs.microsoft.com . Consultado el 8 de junio de 2021 .
- ^ "RFC # 31" .
- ^ "semicorutinas" . Archivado desde el original el 24 de octubre de 2007.
- ^ https://hub.packtpub.com/rust-1-39-releases-with-stable-version-of-async-await-syntax-better-ergonomics-for-match-guards-attributes-on-function-parameters- y más / . Falta o vacío
|title=
( ayuda ) - ^ "Scala Coroutines" . Tormenta en ruta . Consultado el 28 de diciembre de 2019 .
- ^ Preguntas frecuentes sobre Scala Coroutines
- ^ Instantáneas de Scala Coroutine
- ^ "Página de manual de corrutina - 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". Metodología de programación y diseño de lenguajes . Apuntes de conferencias en Ciencias de la Computación . 79 . págs. 25–35. doi : 10.1007 / 3-540-09745-7_2 . ISBN 978-3-540-09745-7. S2CID 571269 .
Otras lecturas
- Ana Lucia de Moura; Roberto Ierusalimschy (2004). "Revisitando Coroutines". Transacciones ACM sobre lenguajes y sistemas de programación . 31 (2): 1–31. CiteSeerX 10.1.1.58.4017 . doi : 10.1145 / 1462166.1462167 . S2CID 9918449 .
enlaces externos
- Introducción integral orientada a C de Simon Tatham a las corrutinas
- Página de corrutinas de Softpanorama : contiene extensos enlaces de corrutinas de ensamblador