¿Es un bucle de eventos solo un bucle para / while con un sondeo optimizado?

54

Estoy tratando de entender qué es un bucle de eventos. A menudo, la explicación es que en un ciclo de eventos, haces algo hasta que se te notifica que ocurrió un evento. Luego manejas el evento y continúas haciendo lo que estabas haciendo antes.

Para asignar la definición anterior con un ejemplo. Tengo un servidor que 'escucha' en un bucle de eventos, y cuando se detecta una conexión de socket, los datos se leen y se muestran, después de lo cual el servidor reanuda / comienza a escuchar como lo hacía antes.

Sin embargo, este evento y el hecho de que nos notifiquen "solo así" son demasiado para mí. Puede decir: "No es 'así como' tiene que registrar un detector de eventos". Pero, ¿qué es un detector de eventos, pero una función que por alguna razón no está regresando? ¿Está en su propio bucle, a la espera de ser notificado cuando ocurre un evento? ¿Debería el oyente del evento también registrar un oyente del evento? ¿Dónde termina?

Los eventos son una buena abstracción con la que trabajar, sin embargo, solo una abstracción. Creo que al final, el sondeo es inevitable. Quizás no lo hagamos en nuestro código, pero los niveles inferiores (la implementación del lenguaje de programación o el sistema operativo) lo están haciendo por nosotros.

Básicamente, se reduce al siguiente pseudo código que se está ejecutando en un lugar lo suficientemente bajo como para que no resulte en una espera ocupada:

while(True):
    do stuff
    check if event has happened (poll)
    do other stuff

Este es mi entendimiento de toda la idea, y me gustaría saber si esto es correcto. Estoy abierto a aceptar que toda la idea es fundamentalmente errónea, en cuyo caso me gustaría la explicación correcta.

    
pregunta TheMeaningfulEngineer 18.10.2013 - 22:03

6 respuestas

51

La mayoría de los bucles de eventos se suspenderán si no hay eventos preparados, lo que significa que el sistema operativo no le dará a la tarea ningún tiempo de ejecución hasta que ocurra un evento.

Diga que el evento es una tecla que se presiona. Puede preguntar si hay un bucle en algún lugar del sistema operativo que compruebe las pulsaciones de teclas. La respuesta es no. Las teclas que se presionan generan una interrupt , que el hardware maneja de forma asíncrona. Lo mismo ocurre con los temporizadores, los movimientos del mouse, la llegada de un paquete, etc.

De hecho, para la mayoría de los sistemas operativos, sondear los eventos es la abstracción. El hardware y el sistema operativo manejan los eventos de forma asíncrona y los ponen en una cola que las aplicaciones pueden sondear. Solo se ve realmente el sondeo verdadero a nivel de hardware en los sistemas integrados, e incluso allí no siempre.

    
respondido por el Karl Bielefeldt 18.10.2013 - 22:42
13

Pienso en un oyente de eventos, no como una función que ejecuta su propio bucle, sino como una carrera de relevos con el primer corredor esperando la pistola de arranque. Una razón importante para usar eventos en lugar de sondear es que son más eficientes con los ciclos de CPU. ¿Por qué? Míralo desde el hardware hacia arriba (en lugar del código fuente hacia abajo).

Considere un servidor web. Cuando su servidor llama a listen() y bloquea, su código está tomando su lugar como un corredor de relevo. Cuando llega el primer paquete de una nueva conexión, la tarjeta de red comienza la carrera interrumpiendo el sistema operativo. El sistema operativo ejecuta una rutina de servicio de interrupción (ISR) que toma el paquete. El ISR pasa la batuta a una rutina de nivel superior que establece la conexión. Una vez que la conexión está activa, esa rutina pasa el testigo a listen() , que pasa el testigo a su código. En ese momento, puedes hacer lo que quieras con la conexión. Por lo que sabemos, entre las carreras, cada corredor de relevo podría ir al pub. Un punto fuerte de la abstracción del evento es que su código no tiene que saberlo o importarlo.

Algunos sistemas operativos incluyen un código de manejo de eventos que se ejecuta en su parte de la carrera, le quitan la batuta y luego regresan a su punto de inicio para esperar a que comience la próxima carrera. En ese sentido, el manejo de eventos se optimiza el sondeo en muchos bucles concurrentes. Sin embargo, siempre hay un disparador externo que inicia el proceso. El detector de eventos no es una función que no está regresando, sino una función que está esperando ese desencadenante externo antes de ejecutarse. En lugar de:

while(True):
    do stuff
    check if event has happened (poll)
    do other stuff

Pienso en esto como:

on(some event):    //I got the baton
     do stuff
     signal the next level up    //Pass the baton

y entre el signal y la próxima vez que se ejecute el controlador, conceptualmente no hay código ejecutándose o en bucle.

    
respondido por el cxw 18.10.2013 - 22:43
8

No. No se trata de "sondeo optimizado". Un bucle de eventos utiliza E / S controladas por interrupciones en lugar de encuestas.

Mientras que, Hasta, Para, etc., los bucles son bucles de sondeo.

"Sondeo" es el proceso de verificar repetidamente algo. Dado que el código de bucle se ejecuta continuamente, y porque es un bucle pequeño y "ajustado", el procesador tiene poco tiempo para cambiar de tareas y hacer cualquier otra cosa. Casi todos los "bloqueos", "bloqueos", "bloqueos" o lo que se quiera llamar cuando la computadora deja de responder, son la manifestación de que el código se ha quedado atascado en un circuito de sondeo no deseado. La instrumentación mostrará un 100% de uso de CPU.

Los bucles de eventos controlados por interrupciones son mucho más eficientes que los bucles de sondeo. El sondeo es un uso extremadamente inútil de los ciclos de CPU, por lo que se hace todo lo posible para eliminarlo o minimizarlo.

Sin embargo, para optimizar la calidad del código, la mayoría de los idiomas intentan usar el paradigma de bucle de sondeo lo más cerca posible de los comandos de manejo de eventos, ya que tienen propósitos funcionalmente similares dentro de un programa. Por lo tanto, como el sondeo es la forma más familiar de esperar una pulsación de tecla o algo, es fácil para el inexperto usarlo y terminar con un programa que puede funcionar bien por sí solo, pero nada más funciona mientras se está ejecutando. Se ha "hecho cargo" de la máquina.

Como se explica en otras respuestas, en el manejo de eventos controlados por interrupciones, esencialmente se establece una "bandera" dentro de la CPU y el proceso se "suspende" (no se permite que se ejecute) hasta que esa bandera se cambie por algún otro proceso (como como el controlador del teclado cambiándolo cuando el usuario ha presionado una tecla). Si el indicador es una condición de hardware real, como que una línea esté "en alto", se denomina "interrupción" o "interrupción de hardware". Sin embargo, la mayoría se implementan como una dirección de memoria en la CPU o en la memoria principal (RAM) y se denominan "semáforos".

Los semáforos se pueden cambiar bajo el control del software y, por lo tanto, pueden proporcionar un mecanismo de señalización muy rápido y sencillo entre los procesos del software.

Sin embargo, las interrupciones solo se pueden cambiar por hardware. El uso más omnipresente de las interrupciones es el que se activa a intervalos regulares por el chip del reloj interno. Uno de los innumerables tipos de acciones de software activadas por interrupciones de reloj, es el cambio de semáforos.

Me he dejado mucho, pero tuve que parar en algún lugar. Por favor, pregunta si necesitas más detalles.

    
respondido por el DocSalvager 25.10.2013 - 07:54
7

Por lo general, la respuesta es el hardware, el sistema operativo y los subprocesos en segundo plano que no controlas para que parezcan sin esfuerzo. La tarjeta de red recibe algunos datos que genera una interrupt para avisar a la CPU. El manejador de interrupciones del sistema operativo lo maneja. Luego, un sistema operativo como parte del manejo del evento despierta un hilo de fondo que no controla (que se creó al registrarse para el evento y que ha estado inactivo desde que se registró para el evento) y ejecuta su controlador de eventos.

    
respondido por el stonemetal 18.10.2013 - 22:43
7

Voy a ir en contra de todas las otras respuestas que veo hasta ahora y decir "sí" . Creo que las otras respuestas están complicando las cosas demasiado. Desde un punto de vista conceptual, todos los bucles de eventos son esencialmente:

while <the_program_is_running> {
    event=wait_for_next_event()
    process_event(event)
}

Si está intentando entender los bucles de eventos por primera vez, pensar en ellos como un simple bucle no hará daño. Algunos marcos subyacentes esperan que el SO entregue un evento, luego enruta el evento a uno o más manejadores, luego espera el próximo evento, y así sucesivamente. Eso es realmente todo lo que hay desde la perspectiva del software de aplicación.

    
respondido por el Bryan Oakley 19.10.2013 - 01:25
1

No todos los desencadenadores de eventos se manejan en bucles. La forma en que a menudo escribo mis propios motores de eventos sería así:

interface Listener {
    void handle (EventInfo info);
}

List<Listener> registeredListeners

void triggerEvent (EventInfo info) {
    foreach (listener in registeredListeners) { // Memo 1
        listener.handle(info) // the handling may or may not be synchronous... your choice
    }
}

void somethingThatTriggersAnEvent () {
    blah
    blah
    blah
    triggerEvent(someGeneratedEventInfo)
    more blah
}

Tenga en cuenta que aunque Memo 1 está en un bucle, el bucle es para notificar a cada oyente. El desencadenador del evento en sí no está necesariamente en un bucle.

En teoría, los eventos clave a nivel de sistema operativo pueden usar la misma técnica (aunque creo que a menudo realizan sondeos en su lugar, solo estoy especulando aquí), siempre que el sistema operativo exponga algún tipo de registerListener API.

    
respondido por el Thomas Eding 18.10.2013 - 22:15

Lea otras preguntas en las etiquetas