stringtranslate.com

Corrutina

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:

  1. los valores de los datos locales de una corrutina persisten entre llamadas sucesivas;
  2. 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:

  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 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.
  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 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 colaLa corrutina produce un bucle  mientras q no esté lleno Crea algunos elementos nuevos Añade los elementos a q ceder para consumirLa corrutina consume un bucle  mientras q no esté vacío eliminar algunos elementos de q utiliza los articulos ceder para producirLlamar 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 colaEl generador produce un bucle  mientras q no esté lleno Crea algunos elementos nuevos Añade los elementos a q producirEl generador consume el bucle  mientras q no esté vacío eliminar algunos elementos de q utiliza los articulos producirdespachador de subrutinas var d := new dictionary( generadoriterador ) 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:

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 .

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 , 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] [ fuente no primaria necesaria ] 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 manejador 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++

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:

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.

JavaScript

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

Las corrutinas se implementan de forma nativa en todos los backends de Raku . [59]

PHP

Pitón

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í

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

Referencias

  1. ^ "¿Cómo diablos funciona async/await en Python 3.5?". Canadiense alto y sarcástico . 2016-02-11 . Consultado el 2023-01-10 .
  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-1. Archivado (PDF) del original el 21 de octubre de 2019.
  3. ^ 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.
  4. ^ 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.
  5. ^ 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. 
  6. ^ 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.
  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 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
  8. ^ Anthony Ralston (2000). Enciclopedia de informática. Nature Pub. Group. ISBN 978-1-56159-248-7. Recuperado el 11 de mayo de 2013 .
  9. ^ 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".
  10. ^ 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 .
  11. ^ "Corrutina: Corrutinas de tipos seguros que utilizan tipos de sesión ligeros".
  12. ^ "Co-rutinas en Haskell".
  13. ^ "El módulo Coroutines (coroutines.hhf)". Manual de la biblioteca estándar de HLA .
  14. ^ "Novedades en JavaScript 1.7". Archivado desde el 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)".
  16. ^ "Novedades en Kotlin 1.1".
  17. ^ "Manual de referencia de Lua 5.2". www.lua.org .
  18. ^ "Tutorial de Python async/await". Stack Abuse . 17 de diciembre de 2015.
  19. ^ "8. Declaraciones compuestas — Documentación de Python 3.8.0". docs.python.org .
  20. ^ "Recopilación y/o Corrutinas". 19-12-2012.
  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. "Replanteando el lenguaje de programación de música por ordenador: SuperCollider". Computer Music Journal, 26(4):61-68. MIT Press, 2002.
  23. ^ 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
  24. ^ abc "Corrutinas en C – brainwagon". 5 de marzo de 2005.
  25. ^ 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.
  26. ^ desde "libco". code.byuu.org .[ enlace muerto permanente ]
  27. ^ "getcontext(3) - Página del manual de Linux". man7.org .
  28. ^ http://swtch.com/libtask/ - Biblioteca de corrutinas libtask de Russ Cox para FreeBSD, Linux, Mac OS X y SunOS
  29. ^ Biblioteca de corrutinas portátil: biblioteca C que utiliza las funciones POSIX/SUSv3
  30. ^ 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
  31. ^ https://github.com/halayli/lthread - lthread es una biblioteca de corrutinas multinúcleo/multihilo escrita en C
  32. ^ "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
  33. ^ "libconcurrency - Una biblioteca de concurrencia escalable para C".Una biblioteca C sencilla para corrutinas portátiles de cambio de pila
  34. ^ "libcoro: biblioteca C que implementa corrutinas (multitarea cooperativa) de manera portable".utilizado como base para el módulo perl Coro.
  35. ^ "RIBS (Infraestructura robusta para sistemas backend) versión 2: aolarchive/ribs2". 13 de agosto de 2019 – vía GitHub.
  36. ^ "libdill". libdill.org . Archivado desde el original el 2019-12-02 . Consultado el 2019-10-21 .
  37. ^ "Una biblioteca de corrutinas asimétricas de C increíblemente rápida y liviana 💎 ⛅🚀⛅🌞: hnes/libaco". 21 de octubre de 2019 – vía GitHub.
  38. ^ por Simon Tatham (2000). "Corrutinas en C".
  39. ^ "Implementación de corrutinas sin pila en C y C++: jsseldenthuis/coroutine". 18 de marzo de 2019 – vía GitHub.
  40. ^ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4680.pdf - Especificación técnica para corrutinas
  41. ^ https://en.cppreference.com/w/cpp/compiler_support#cpp20 - Compatibilidad actual del compilador con corrutinas estándar
  42. ^ http://mozy.com/blog/announcements/open-source-and-mozy-the-debut-of-mozy-code/ - Código abierto y Mozy: el debut de Mozy Code
  43. ^ https://twitter.com/eric01/status/867473461836263424 - EricWF: ¡Las corrutinas ya están en Clang Trunk! Estamos trabajando en la implementación de Libc++.
  44. ^ Wagner, Bill (11 de noviembre de 2021). "Iteradores". Documentación de C# . Microsoft – vía Microsoft Learn.
  45. ^ 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.
  46. ^ "Goroutines - Go eficaz". go.dev . Consultado el 28 de noviembre de 2022 .
  47. ^ "Declaraciones Go - La especificación Go". go.dev . Consultado el 28 de noviembre de 2022 .
  48. ^ "Goroutines - Un recorrido por Go". go.dev . Consultado el 28 de noviembre de 2022 .
  49. ^ "Preguntas frecuentes (FAQ) - El lenguaje de programación Go". go.dev .
  50. ^ Lukas Stadler (2009). "Continuaciones de JVM" (PDF) . Cumbre del lenguaje JVM.
  51. ^ 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.
  52. ^ "Historial de versiones de Lua". Lua.org .
  53. ^ de Moura, Ana Lucía; Rodríguez, Noemí; Jerusalén, Roberto. "Corrutinas en Lua" (PDF) . Lua.org . Consultado el 24 de abril de 2023 .
  54. ^ de Moura, Ana Lucía; Rodríguez, Noemí; Jerusalén, Roberto (2004). "Corrutinas en Lua". Revista de Informática Universal . 10 (7): 901--924.
  55. ^ http://www.mono-project.com/Continuations Continuaciones Mono
  56. ^ http://blogs.msdn.com/cbrumme/archive/2004/02/21/77595.aspx, Chris Brumme, WebLog de cbrumme
  57. ^ kexugit (15 de septiembre de 2005). "El modo de fibra ha desaparecido..." docs.microsoft.com . Consultado el 8 de junio de 2021 .
  58. ^ "La biblioteca de hilos".
  59. ^ "RFC #31".
  60. ^ "Novedades de Python 3.7" . Consultado el 10 de septiembre de 2021 .
  61. ^ "semi-coroutines". Archivado desde el original el 24 de octubre de 2007.
  62. ^ "Página del manual de corrutinas - Comandos integrados de Tcl". Tcl.tk . Consultado el 27 de junio de 2016 .
  63. ^ 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

Enlaces externos