Pregunta

El concepto de una coroutine suena muy interesante, pero no sé si tiene sentido en un entorno productivo real? ¿Cuáles son los casos de uso para las corutinas, que pueden resolverse de manera más elegante, más simple o más eficiente como con otros métodos?

¿Fue útil?

Solución

Las verdaderas rutinas requieren el apoyo de sus herramientas; deben ser implementadas por el compilador y respaldadas por el marco subyacente.

Un ejemplo del mundo real de Coroutines se encuentra con el rendimiento de rendimiento " palabra clave proporcionada en C # 2.0, que le permite escribir un método que devuelve múltiples valores para el bucle.

El rendimiento de rendimiento " sin embargo, tiene limitaciones: la implementación utiliza una clase auxiliar para capturar el estado, y solo admite un caso específico de corutina como generador (iterador).

En el caso más general, la ventaja de Coroutines es que hacen que ciertos cálculos basados ??en estado sean mucho más fáciles de expresar y más fáciles de entender: implementar una máquina de estados como un conjunto de corutinas puede ser más elegante que los enfoques más comunes . Pero hacer esto requiere soporte y herramientas que aún no existen en C # o Java.

Otros consejos

Algunas buenas respuestas que describen qué son las corutinas.

Pero para un caso de uso real. Toma un servidor web. Tiene múltiples conexiones simultáneas y quiere programar la lectura y escritura de todas ellas.

Esto se puede implementar usando corutinas. Cada conexión es una rutina que lee / escribe una pequeña cantidad de datos, y luego produce "". control al planificador, que pasa a la siguiente rutina (que hace lo mismo) a medida que avanzamos por todas las conexiones disponibles.

Muchos de ellos, por ejemplo:

grep TODO *.c *.h | wc -l

La canalización anterior es exactamente una rutina: el comando grep genera una secuencia de líneas que van a un búfer, el comando wc " las consume " ;; si el búfer se llena, el grep " bloquea " hasta que el búfer se vacíe, y si el búfer está vacío, el comando wc espera una nueva entrada.

Lo que pasa con las corutinas es que ahora se usan con mayor frecuencia en patrones más restringidos, como los generadores de Python mencionados, o como tuberías.

Si desea verlos más, vea los artículos de Wikipedia, especialmente en coroutines y iteradores .

Sé que han pasado casi 5 años desde que se hizo la pregunta, pero me sorprende que nadie haya mencionado el caso de uso de los juegos en los que las corutinas se usan mucho para dividir el tiempo en un cálculo.

Para mantener una velocidad de cuadro constante en un juego, digamos 60 fps, tienes alrededor de 16,6 ms para ejecutar el código en cada cuadro. Eso incluye simulación física, procesamiento de entrada, dibujo / pintura.

Digamos que su método se ejecuta en cada cuadro. Si su método lleva mucho tiempo y termina abarcando múltiples cuadros, va a escalonar el resto del cálculo en el bucle del juego, lo que hace que el usuario vea "jank". (una caída repentina en la velocidad de fotogramas).

Lo que las corutinas le permiten hacer es de alguna manera dividir el tiempo en este cálculo para que se ejecute un poco en cada cuadro.

Para que eso suceda, las corutinas esencialmente permiten que el método `` produzca '' el cálculo de vuelta a la "persona que llama" (en este caso, el bucle del juego) para que la próxima vez que se llame al método se reanude desde donde lo dejó.

Las rutinas son útiles para implementar patrones de productor / consumidor.

Por ejemplo, Python introdujo corutinas en una función de lenguaje llamada generadores , que estaba destinado a simplificar la implementación de iteradores.

También pueden ser útiles para implementar la multitarea cooperativa, donde cada tarea es una rutina que cede ante un planificador / reactor.

Las rutinas pueden ser útiles cada vez que un sistema tiene dos o más piezas de código cuya representación más natural sería como una serie secuencial de pasos que implican mucha espera.

Por ejemplo, considere un dispositivo que tiene una interfaz de usuario de LCD y teclado y un módem, y necesita usar el módem para llamar periódicamente e informar su estado independientemente de lo que esté haciendo el usuario en el teclado. La mejor manera de escribir la interfaz de usuario puede ser usar funciones como " input_numeric_value (& amp; CONV_SPEED_FORMAT, & amp; cinta transportadora_velocidad); " que volverá cuando un usuario haya ingresado un valor, y la mejor manera de manejar la comunicación puede ser usar funciones como " wait_for_carrier (); " que volverá cuando la unidad se haya conectado o haya determinado que no lo hará.

Sin las rutinas, el subsistema UI o el subsistema de módem tendrían que implementarse utilizando una máquina de estado. El uso de corutinas hace posible que ambos subsistemas se escriban con el estilo más natural. Tenga en cuenta que es importante que ninguno de los subsistemas pase mucho tiempo sin poner las cosas en un "consistente" state y llamando a yield (), ni llama a yield () sin poner las cosas en un " consistente " primero, pero generalmente no es difícil cumplir con esas restricciones.

Tenga en cuenta que si bien uno podría usar la multitarea completa, eso requiere el uso de bloqueos en todo el lugar cada vez que se altera el estado compartido. Dado que el conmutador de rutina nunca cambiará las cosas excepto en las llamadas a yield (), cualquiera de las rutinas puede alterar libremente el estado compartido siempre y cuando se asegure de que todo esté en orden antes del próximo rendimiento, y esté preparado para que la otra rutina altere el estado " ; durante " el rendimiento ().

Como un ejemplo más específico en la línea de productor / consumidor, algo tan simple como el humilde programa de informes por lotes podría usar co-rutinas.

La sugerencia clave para ese ejemplo es tener un trabajo no trivial para consumir datos de entrada (por ejemplo, analizar datos o acumular cargos y pagos en una cuenta), y un trabajo no trivial para producir la salida. Cuando tienes estas características:

  • Es fácil organizar / comprender el código del lado de entrada si puede " emitir " unidades de trabajo en varios lugares.
  • También es fácil organizar / comprender el código del lado de salida si puede "agarrar" la siguiente unidad de trabajo en una estructura de control anidada.

entonces las rutinas y las colas son buenas técnicas para tener a su disposición.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top