¿Qué es una corutina? ¿Cómo se relacionan con la concurrencia?
¿Qué es una corutina? ¿Cómo se relacionan con la concurrencia?
Respuestas:
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á.
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.
orthogonal = Not similar to each other
?
orthogonal
significa "independientes el uno del otro".
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 .
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.
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.
Básicamente, hay dos tipos de corutinas:
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
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.
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
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 .
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.
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?
Como muestra la imagen, no es necesario llamar return
para 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
.
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 python
biblioteca 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 jvm
aplicación, en el que core i7
se utilizan los ocho núcleos de hyperthread: puede ver una utilización del 797% en Activity Monitor
o Top
. En cambio, cuando se ejecuta un python
programa típico , incluso uno con coroutines
o python threading
, la utilización se maximizará al 100%. Es decir, una máquina hyperthread.