¿Qué es una corutina?

204

¿Qué es una corutina? ¿Cómo se relacionan con la concurrencia?

yesraaj
fuente
2
El código concurrente no necesariamente tiene que ejecutarse en "paralelo" (no introduzcamos nuevos términos).
lucid_dreamer
2
He escrito una biblioteca de rutina con C estándar, que admite mensajes de GUI select / poll / eplll / kqueue / iocp / Win para Linux, BSD y Windows. Es un proyecto de código abierto en github.com/acl-dev/libfiber . Los consejos serán bienvenidos.
ShuXin Zheng
Más información interesante aquí: stackoverflow.com/q/16951904/14357
gasto
Me imagino que esta pregunta será rechazada si se hace en esta era actual. No estoy seguro de por qué hay tanta diferencia de percepción de la comunidad en comparación con antes.
tnkh
una corutina es una función que puede suspender su ejecución antes de alcanzar el retorno, e indirectamente puede pasar el control a otra corutina por algún tiempo.
hassanzadeh.sd

Respuestas:

138

Las rutinas y la concurrencia son en gran medida ortogonales. Las rutinas son una estructura de control general mediante la cual el control de flujo se pasa cooperativamente entre dos rutinas diferentes sin retorno.

La declaración 'rendimiento' en Python es un buen ejemplo. Crea una corutina. Cuando se encuentra el "rendimiento", se guarda el estado actual de la función y se devuelve el control a la función de llamada. La función de llamada puede transferir la ejecución nuevamente a la función de rendimiento y su estado se restaurará al punto donde se encontró el 'rendimiento' y la ejecución continuará.

usuario21714
fuente
19
¿Cuál es la diferencia entre llamar a una función directamente y ceder desde una corutina con envolver esta función en esta corutina?
Ming Li
3
Podría ser mejor explicar que estos dos conceptos no son realmente 'ortogonales' en este contexto. Definitivamente puedes dibujar cómo los dos conceptos son similares entre sí. La idea de pasar el control entre dos o más cosas es muy similar.
steviejay
8
Coroutines are a general control structure whereby flow control is cooperatively passed between two different routines without returning.<- Esto es concurrencia. La palabra que estás buscando es paralelismo.
Adam Arold
@steviejay orthogonal = Not similar to each other?
tonix
1
@tonix Me dijeron que orthogonalsignifica "independientes el uno del otro".
Rick
77

Desde Programación en Lua , " Coroutines" sección:

Una corutina es similar a un hilo (en el sentido de subprocesamiento múltiple): es una línea de ejecución, con su propia pila, sus propias variables locales y su propio puntero de instrucción; pero comparte variables globales y sobre todo cualquier otra cosa con otras corutinas. La principal diferencia entre hilos y corutinas es que, conceptualmente (o literalmente, en una máquina multiprocesador), un programa con hilos ejecuta varios hilos en paralelo. Las corutinas, por otro lado, son colaborativas: en un momento dado, un programa con corutinas ejecuta solo una de sus corutinas, y esta corrutina en ejecución suspende su ejecución solo cuando solicita explícitamente que se suspenda.

Entonces el punto es: las corutinas son "colaborativas". Incluso en un sistema multinúcleo, solo se ejecuta una rutina en un momento dado (pero pueden ejecutarse varios subprocesos en paralelo). No hay preferencia entre las rutinas, la rutina debe abandonar la ejecución explícitamente.

Para " concurrency", puede referirse a Rob Pike diapositiva de :

La concurrencia es la composición de los cálculos de ejecución independiente.

Entonces, durante la ejecución de la corutina A, transfiere el control a la corutina B. Luego, después de un tiempo, la corutina B devuelve el control a la corutina A. Como hay dependencia entre las corutinas y deben ejecutarse en tándem, entonces las dos corutinas no son concurrentes .

Nan Xiao
fuente
66
Las rutinas no se ejecutan independientemente. Se turnan, cada uno esperando que el otro haga parte del trabajo. Se coordinan activamente entre sí. Eso es lo opuesto a la definición de concurrencia de Rob Pikes.
Erick G. Hagstrom
2
@ ErickG.Hagstrom: Aunque no se ejecutan de forma independiente, la lógica de cada corutina puede ser independiente, ¿verdad? Si es correcto, es como un sistema operativo no preventivo que se ejecuta en una CPU de un núcleo, un proceso debe abandonar la CPU para permitir que se ejecuten otras tareas.
Nan Xiao
66
Hay una diferencia entre renunciar a la CPU para dejar que se ejecute otra tarea y decirle a otro proceso específico que es hora de ejecutar. Las corutinas hacen lo último. Eso no es independiente en ningún sentido.
Erick G. Hagstrom
77
@ChrisClark Estoy de acuerdo contigo. Las rutinas son concurrencia. Aquí hay una cita de Wikipedia: Las corutinas son muy similares a los hilos. Sin embargo, las corutinas son multitarea cooperativamente, mientras que los hilos son típicamente multitarea preventiva. Esto significa que proporcionan concurrencia pero no paralelismo .
smwikipedia
3
Y: la multitarea cooperativa, también conocida como multitarea no preventiva, es un estilo de multitarea de computadora en el que el sistema operativo nunca inicia un cambio de contexto de un proceso en ejecución a otro proceso. En cambio, los procesos voluntariamente ceden el control periódicamente o cuando están inactivos o bloqueados lógicamente para permitir que varias aplicaciones se ejecuten simultáneamente.
smwikipedia
47

La mayoría de las respuestas me parecen demasiado técnicas, aunque sea una pregunta técnica. Me costó mucho tratar de entender el proceso de rutina. Lo entiendo, pero no lo consigo al mismo tiempo.

Encontré esta respuesta aquí muy útil:

https://dev.to/thibmaek/explain-coroutines-like-im-five-2d9

Para citar a Idan Arye:

Para construir sobre su historia, lo pondría algo como esto:

Empiezas a ver la caricatura, pero es la introducción. En lugar de ver la introducción, cambias al juego y entras en el lobby en línea, pero necesita 3 jugadores y solo tú y tu hermana están en él. En lugar de esperar a que otro jugador se una, cambie a su tarea y responda la primera pregunta. La segunda pregunta tiene un enlace a un video de YouTube que debes ver. Lo abres y comienza a cargarse. En lugar de esperar a que se cargue, vuelve a la caricatura. La introducción ha terminado, para que pueda ver. Ahora hay comerciales, pero mientras tanto un tercer jugador se ha unido para que cambies al juego Y así sucesivamente ...

La idea es que no solo cambies las tareas realmente rápido para que parezca que estás haciendo todo a la vez. Utiliza el tiempo que espera que suceda algo (IO) para hacer otras cosas que requieren su atención directa.

Definitivamente revise el enlace, hay mucho más que no puedo citar todo.

mr1031011
fuente
66
Ilustración muy simple y directa. +1 por esto.
Taslim Oseni
Gran ilustración. Construí una historia similar, con la cola esperando para recoger un paquete. pero por hoy, el tuyo es mucho más realista, ¿quién hace cola cuando hay entregas de puerta a puerta? Lol
apolak
1
Esa es una explicación asombrosa. De la cita en sí, está súper claro.
Farruh Habibullaev
15

La rutina es similar a la subrutina / hilos. La diferencia es que una vez que la persona que llama invocó una subrutina / subprocesos, nunca volverá a la función de llamada. Pero una rutina puede volver a la persona que llama después de ejecutar un código que le permite ejecutar parte de su propio código y volver al punto de la rutina donde detuvo la ejecución y continuar desde allí. es decir. Una corutina tiene más de un punto de entrada y salida.

Centelleo
fuente
No es tan similar a los subprocesos, que se ejecutan de forma independiente y simultánea (núcleos separados en paralelo). Además, la comparación de subrutinas falla en el sentido de que hay múltiples rutas de ejecución independientes y no están devolviendo resultados entre sí.
Java
11
  • Las rutinas son excelentes características disponibles en el idioma Kotlin
  • Las rutinas son una nueva forma de escribir código asincrónico sin bloqueo (y mucho más)
  • Coroutine son hilos ligeros. Un subproceso ligero significa que no se asigna en el subproceso nativo, por lo que no requiere cambio de contexto en el procesador, por lo que son más rápidos.
  • no se asigna en hilo nativo
  • Las rutinas y los hilos son multitarea. Pero la diferencia es que los subprocesos son administrados por el sistema operativo y las corrutinas por los usuarios.

Básicamente, hay dos tipos de corutinas:

  1. Apilables
  2. Apilables

Kotlin implementa corutinas sin pila, es decir que las corutinas no tienen pila propia, por lo que no se asignan en el hilo nativo.

Estas son las funciones para iniciar la rutina:

launch{}

async{}

Puedes aprender más desde aquí:

https://www.kotlindevelopment.com/deep-dive-coroutines/

https://blog.mindorks.com/what-are-coroutines-in-kotlin-bf4fecd476e9

Dhaval Jivani
fuente
1
¡Buena respuesta! Útil para los desarrolladores de Kotlin y Android.
Malwinder Singh
5

En una nota diferente, en la geventbiblioteca de Python hay una coroutinebiblioteca de red basada que le brinda características similares a hilos como solicitudes de red asíncronas, sin la sobrecarga de crear y destruir hilos. La coroutinebiblioteca utilizada es greenlet.

Joseph
fuente
2

De Python Coroutine :

La ejecución de las rutinas de Python puede suspenderse y reanudarse en muchos puntos (ver la rutina). Dentro del cuerpo de una función de rutina, los identificadores de espera y asíncrono se convierten en palabras clave reservadas; Las expresiones de espera, asíncrono y asíncrono solo se pueden usar en cuerpos de funciones de rutina.

De las rutinas (C ++ 20)

Una corutina es una función que puede suspender la ejecución para reanudarla más tarde . Las rutinas son apiladas: suspenden la ejecución volviendo a la persona que llama. Esto permite un código secuencial que se ejecuta de forma asíncrona (por ejemplo, para manejar E / S sin bloqueo sin devoluciones de llamada explícitas), y también admite algoritmos en secuencias infinitas calculadas de manera diferida y otros usos.

Compare con la respuesta de otros:

En mi opinión, la parte posterior resumida es una diferencia fundamental, al igual que la de @ Twinkle.
Aunque muchos campos del documento todavía están en progreso, esta parte es similar a la mayoría de las respuestas, excepto la de @Nan Xiao

Las corutinas, por otro lado, son colaborativas: en un momento dado, un programa con corutinas ejecuta solo una de sus corutinas, y esta corrutina en ejecución suspende su ejecución solo cuando solicita explícitamente que se suspenda.

Como se cita del Programa en Lua, tal vez esté relacionado con el idioma (no está familiarizado con Lua actualmente), no todos los documentos mencionan el único parte.

La relación con concurrente:
hay una parte de "Ejecución" de las Corutinas (C ++ 20). Demasiado tiempo para citar aquí.
Además del detalle, hay varios estados.

When a coroutine begins execution  
When a coroutine reaches a suspension point  
When a coroutine reaches the co_return statement  
If the coroutine ends with an uncaught exception  
When the coroutine state is destroyed either because it terminated via co_return or uncaught exception, or because it was destroyed via its handle 

como el comentario de @Adam Arold bajo la respuesta de @ user217714. Es concurrencia.
Pero es diferente del multihilo. de std :: thread

Los hilos permiten que múltiples funciones se ejecuten simultáneamente. Los subprocesos comienzan a ejecutarse inmediatamente después de la construcción del objeto de subproceso asociado (a la espera de cualquier retraso en la programación del sistema operativo), comenzando en la función de nivel superior proporcionada como argumento de constructor. El valor de retorno de la función de nivel superior se ignora y si termina lanzando una excepción, se llama a std :: terminate. La función de nivel superior puede comunicar su valor de retorno o una excepción a la persona que llama a través de std :: promise o modificando variables compartidas (que pueden requerir sincronización, consulte std :: mutex y std :: atomic)

Dado que es concurrencia, funciona como subprocesos múltiples, especialmente cuando la espera es inevitable (desde la perspectiva del sistema operativo), por eso también es confusa.

Shihe Zhang
fuente
1

Una corutina es un tipo especial de subprograma. En lugar de la relación maestro-esclavo entre un llamador y un subprograma llamado que existe con subprogramas convencionales, el llamador y las corutinas llamadas son más equitativas.

  • Una corutina es un subprograma que tiene múltiples entradas y las controla a sí misma, compatible directamente en Lua

  • También llamado control simétrico: las llamadas y las corutinas llamadas son más equitativas

  • Una llamada de rutina se denomina currículum

  • El primer currículum vitae de una rutina está en su inicio, pero las llamadas posteriores entran en el punto justo después de la última declaración ejecutada en la rutina.

  • Las rutinas se reanudan una y otra vez, posiblemente para siempre

  • Las rutinas proporcionan la ejecución cuasi concurrente de las unidades del programa (las corutinas); su ejecución se intercala, pero no se superpone

Ejemplo 1 Ejemplo2

BoraKurucu
fuente
1

Encuentro que una explicación de este enlace es bastante sencilla. Ninguna de esas respuestas intenta explicar la concurrencia versus el paralelismo, excepto el último punto en esta respuesta .

  1. ¿Qué es concurrente (programa)?

citado de "programación Erlang", por Joe Armstrong, el legendario:

un programa concurrente puede ejecutarse potencialmente más rápido en una computadora paralela.

  • Un programa concurrente es un programa escrito en un lenguaje de programación concurrente. Escribimos programas concurrentes por razones de rendimiento, escalabilidad o tolerancia a fallas.

  • Un lenguaje de programación concurrente es un lenguaje que tiene construcciones de lenguaje explícito para escribir programas concurrentes. Estas construcciones son una parte integral del lenguaje de programación y se comportan de la misma manera en todos los sistemas operativos.

  • una computadora paralela es una computadora que tiene varias unidades de procesamiento (CPU o núcleos) que pueden ejecutarse al mismo tiempo.

Entonces concurrencia no es lo mismo que paralelismo. Todavía puede escribir programas concurrentes en una computadora de un solo núcleo. El programador de tiempo compartido le hará sentir que su programa se está ejecutando simultáneamente.

El programa concurrente tiene el potencial de ejecutarse en paralelo en una computadora paralela, pero no está garantizado. . El sistema operativo solo puede darle un núcleo para ejecutar su programa.

Por lo tanto, la concurrencia es un modelo de software de un programa concurrente que no significa que su programa pueda ejecutarse en paralelo físicamente.

  1. corutina y concurrencia

La palabra "corutina" se compone de dos palabras: "co" (cooperativa) y "rutinas" (funciones).

a. ¿logra concurrencia o paralelismo?

Para ser simple, hablemos sobre un solo núcleo computadora de .

La concurrencia se logra mediante tiempos compartidos del sistema operativo. Un subproceso ejecuta su código en los marcos de tiempo asignados en el núcleo de la CPU. Puede ser reemplazado por el sistema operativo. También puede ceder el control al sistema operativo.

Una corutina, por otro lado, cede el control a otra corutina dentro del hilo, no al sistema operativo. Por lo tanto, todas las rutinas dentro de un hilo aún explotan el marco de tiempo para ese hilo sin ceder el núcleo de la CPU a otros hilos administrados por el sistema operativo.

Por lo tanto, se puede pensar en la rutina que logra el tiempo compartido por el usuario, no por el sistema operativo (o cuasi-paralelismo). Las corutinas se ejecutan en el mismo núcleo asignado al subproceso que ejecuta esas corutinas.

¿Coroutine logra paralelismo? Si es un código enlazado a la CPU, no. Al igual que los tiempos compartidos, te hace sentir que se ejecutan en paralelo, pero sus ejecuciones se intercalan y no se superponen. Si está vinculado a IO, sí, logra un paralelo por hardware (dispositivos IO) no por su código.

si. la diferencia con la llamada a la función?

ingrese la descripción de la imagen aquí

Como muestra la imagen, no es necesario llamar returnpara cambiar de control. Puede ceder sin return. Una rutina guarda y comparte el estado en el marco de la función actual (pila). Por lo tanto, es mucho más liviano que la función, ya que no tiene que guardar registros y variables locales para apilar y rebobinar la pila de llamadas cuando call ret.

Izana
fuente
0

Ampliaré la respuesta de @ user21714. Las rutinas son rutas de ejecución independientes que no pueden ejecutarse simultáneamente. Dependen de un controlador, por ejemplo, una pythonbiblioteca de controladores, para manejar el cambio entre estas rutas. Pero para que esto funcione, las corutinas mismas deben invocaryield o estructuras similares que permitan pausar su ejecución.

En cambio, los subprocesos se ejecutan en recursos informáticos independientes y en paralelo entre sí. Dado que se encuentran en diferentes recursos, no es necesario invocar el rendimiento para permitir que continúen los otros caminos de ejecución.

Puede ver este efecto iniciando un programa de subprocesos múltiples, por ejemplo, una jvmaplicación, en el que core i7se utilizan los ocho núcleos de hyperthread: puede ver una utilización del 797% en Activity Monitoro Top. En cambio, cuando se ejecuta un pythonprograma típico , incluso uno con coroutineso python threading, la utilización se maximizará al 100%. Es decir, una máquina hyperthread.

javadba
fuente