2009-12-20 64 views

Respuesta

58

Las corrutinas son una forma de procesamiento secuencial: solo una se está ejecutando en un momento dado (al igual que las subrutinas, procedimientos AKA, funciones AKA, simplemente pasan el testigo entre sí de forma más fluida).

Los subprocesos son (al menos conceptualmente) una forma de procesamiento simultáneo: múltiples subprocesos pueden estar ejecutándose en un momento dado. (Tradicionalmente, en máquinas de núcleo único de una CPU, esa simultaneidad se simuló con alguna ayuda del sistema operativo; hoy en día, dado que muchas máquinas son multi-CPU y/o multinúcleo, se ejecutarán de facto simultáneamente, no solo "conceptualmente").

7

Depende del idioma que esté utilizando. Por ejemplo, en Lua they are the same thing (el tipo de variable de una coroutine se llama thread).

Por lo general, las coroutines implementan el rendimiento voluntario donde (usted) el programador decide dónde yield, es decir, le da el control a otra rutina.

El sistema operativo administra (detiene e inicia) automáticamente los subprocesos, e incluso se pueden ejecutar al mismo tiempo en las CPU multinúcleo.

11

En una palabra: preemption. Las coroneladas actúan como malabaristas que se siguen entregando puntos bien ensayados. Los hilos (hilos verdaderos) se pueden interrumpir en casi cualquier punto y luego se reanudan más tarde. Por supuesto, esto trae consigo todo tipo de problemas de conflicto de recursos, de ahí el famoso GIL - Global Interpreter Lock de Python.

Muchas implementaciones de subprocesos son en realidad más como corrutinas.

74

Primera lectura:Concurrency vs Parallelism - What is the difference?

concurrencia es la separación de tareas para proporcionar intercalada ejecución. Paralelismo es la ejecución simultánea de múltiples trabajos para aumentar la velocidad. - https://github.com/servo/servo/wiki/Design

Respuesta corta: Con hilos, el sistema operativo cambia hilos ejecutados de forma preventiva de acuerdo a su parrilla de programación, que es un algoritmo en el núcleo del sistema operativo. Con coroutines, el programador y el lenguaje de programación determinan cuándo cambiar las corutinas; en otras palabras, las tareas son multitareas cooperativas al pausar y reanudar funciones en puntos establecidos, normalmente (pero no necesariamente) dentro de un solo hilo.

Respuesta larga: En contraste con las discusiones, que son programadas por el sistema operativo de forma preventiva, interruptores co-rutina son cooperativas, lo que significa que el programador (y, posiblemente, el lenguaje de programación y su tiempo de ejecución) controla cuando un interruptor va a suceder.

En contraste con los hilos, que son preferente, los interruptores de co-rutina son cooperativos (controles programador cuando un interruptor va a pasar). El kernel no está involucrado en los switches coroutine. - http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/coroutine/overview.html

Un lenguaje que soporte subprocesos nativos pueden ejecutar sus hilos (hilos de usuario) en las roscas del sistema operativo (hilos del núcleo). Cada proceso tiene al menos un hilo de kernel. Los subprocesos de Kernel son como procesos, excepto que comparten espacio de memoria en su proceso de propiedad con todos los demás subprocesos en ese proceso. Un proceso "posee" todos sus recursos asignados, como memoria, identificadores de archivos, sockets, identificadores de dispositivos, etc., y todos estos recursos se comparten entre sus hilos de kernel.

El programador del sistema operativo es parte del kernel que ejecuta cada subproceso durante un tiempo determinado (en una sola máquina del procesador). El planificador asigna tiempo (división por tiempos) a cada subproceso, y si el subproceso no termina en ese momento, el planificador lo anticipa (lo interrumpe y cambia a otro subproceso). Se pueden ejecutar varios subprocesos en paralelo en una máquina multiprocesador, ya que cada subproceso se puede (pero no necesariamente) programar en un procesador separado.

En una máquina con un solo procesador, los subprocesos están divididos por tiempo y se adelantan (cambian entre) rápidamente (en Linux el tiempo predeterminado es de 100 ms) lo que los hace concurrentes. Sin embargo, no se pueden ejecutar en paralelo (simultáneamente), ya que un procesador de un solo núcleo solo puede ejecutar una cosa a la vez.

corrutinas y/o generadores se pueden utilizar para implementar funciones de cooperación. En lugar de ejecutarse en subprocesos del kernel y programados por el sistema operativo, se ejecutan en un único subproceso hasta que ceden o terminan, cediendo a otras funciones según lo determinado por el programador. Los lenguajes con generadores, como Python y ECMAScript 6, se pueden usar para construir corutinas. Async/await (visto en C#, Python, ECMAscript 7, Rust) es una abstracción construida sobre las funciones del generador que producen futuros/promesas.

En algunos contextos, corrutinas pueden referirse a las funciones stackful mientras generadores pueden referirse a las funciones sin pérdida de velocidad.

Fibras, hilos ligeros, y hilos verdes son otros nombres para corrutinas o cosas similares a co-rutina. A veces pueden parecer (normalmente a propósito) más parecidos a los hilos del sistema operativo en el lenguaje de programación, pero no se ejecutan en paralelo como hilos reales y funcionan en su lugar como corrutinas. (Puede haber particularidades o diferencias técnicas más específicas entre estos conceptos según el idioma o la implementación).

Por ejemplo, Java tenía "hilos verdes"; estos fueron los hilos que fueron programados por la máquina virtual Java (JVM) en lugar de los hilos del núcleo del sistema operativo subyacente. Estos no se ejecutan en paralelo ni aprovechan múltiples procesadores/núcleos, ¡ya que eso requeriría un hilo nativo! Como no estaban programados por el sistema operativo, eran más como corrutinas que hilos del kernel. Los hilos verdes son los que Java utilizó hasta que se introdujeron los hilos nativos en Java 1.2.

Los hilos consumen recursos. En la JVM, cada subproceso tiene su propia pila, generalmente de 1 MB de tamaño. 64k es la menor cantidad de espacio de pila permitido por subproceso en la JVM. El tamaño de la pila de subprocesos se puede configurar en la línea de comandos para la JVM. A pesar del nombre, los hilos no son libres, debido a sus recursos de uso, como cada hilo que necesita su propia pila, almacenamiento local de subprocesos (si existe) y el costo de la programación de subprocesos/cambio de contexto/invalidación de caché de CPU.Esta es parte de la razón por la cual las coroutinas se han vuelto populares para aplicaciones altamente concurrentes y críticas para el rendimiento.

Mac OS sólo permitirá un proceso de asignar alrededor de 2000 hilos, y Linux asigna pila 8 MB por hilo y sólo permitirá el mayor número de hilos que caben en la memoria RAM física.

Por lo tanto, los hilos son el peso más pesado (en términos de uso de la memoria y el contexto de conmutación de tiempo), entonces corrutinas, y finalmente generadores son el peso más ligero.

+1

+1, pero esta respuesta podría beneficiarse de algunas referencias. – kojiro

+1

Los hilos verdes son algo diferente de corutinas. ¿no es así?Incluso las fibras tienen algunas diferencias. ver http://programmers.stackexchange.com/questions/254140/is-there-a-difference-between-fibers-coroutines-and-green-threads-and-if-that-i – penguin

43

Alrededor de 7 años de retraso, pero las respuestas aquí faltan un poco de contexto en las co-rutinas vs hilos. ¿Por qué son corrutinas reciben tanta atención últimamente, y cuando se les utilice en comparación con hilos?

En primer lugar, si corrutinas ejecutan concurrentemente (nunca en paralelo ), ¿por qué nadie los prefieren sobre las roscas?

La respuesta es que corrutinas pueden proporcionar una muy alto nivel de concurrencia con muy poca sobrecarga . Generalmente, en un entorno con hebras tiene como máximo 30-50 subprocesos antes de que la cantidad de gastos indirectos realmente se programe estos subprocesos (por el planificador del sistema) significativamente corta en la cantidad de tiempo que los subprocesos realmente hacen un trabajo útil.

autorización así con hilos puede tener paralelismo, pero no demasiado paralelismo, no es que sigue siendo mejor que un compañero de rutina de correr en un solo hilo? Bueno, no necesariamente Recuerde que una co-rutina todavía puede hacer concurrencia sin sobrecarga del programador, simplemente administra el cambio de contexto en sí mismo.

Por ejemplo, si tiene una rutina haciendo algún trabajo y realiza una operación que sabe bloqueará durante un tiempo (es decir, una solicitud de red), con una rutina simultánea puede cambiar a otra rutina sin la sobrecarga de incluir el planificador del sistema en esta decisión - sí usted, el programador debe especificar cuando las co-rutinas pueden cambiar.

Con una gran cantidad de rutinas haciendo muy pequeños trozos de trabajo y cambiar voluntariamente entre sí, que haya alcanzado un nivel de eficiencia sin programador podría esperar alcanzar. Ahora puede tener miles de coroutines trabajando juntas en lugar de decenas de hilos.

Debido a sus rutinas ahora cambian entre sí un pre-determinados puntos que ahora también pueden evitar el bloqueo en las estructuras de datos compartidos (porque nunca se le informe a su código para cambiar a otro corrutina en medio de una sección crítica)

Otro beneficio es el uso de memoria mucho menor. Con el modelo con subprocesos, cada subproceso necesita asignar su propia pila y, por lo tanto, su uso de memoria crece linealmente con la cantidad de subprocesos que tiene. Con las co-rutinas, la cantidad de rutinas que tiene no tiene una relación directa con el uso de su memoria.

Y, por último, corrutinas están recibiendo mucha atención debido a que en algunos lenguajes de programación (como Python) sus hilos no pueden ejecutarse en paralelo de todos modos - coincide en el tiempo al igual que co-rutinas, pero sin la memoria baja y libre sobrecarga de programación.

+2

Cómo hacer un cambio a otro tarea en coroutines cuando nos encontramos con una operación de bloqueo? –

+0

La manera de cambiar a otra tarea es hacer que cualquier operación de bloqueo se realice de manera asincrónica. Esto significa que debe evitar el uso de cualquier operación que realmente bloquee, y solo debe usar operaciones que no admitan el bloqueo cuando se utiliza en su sistema Coroutine. La única forma de evitar esto es tener correcciones admitidas por el kernel, como UMS en Windows, por ejemplo, donde salta a su planificador cada vez que su UMS "thread" bloquea en un syscall. – retep998

Cuestiones relacionadas