¿Es un éxito el rendimiento para crear hilos que se repiten mucho para verificar las cosas?

8

Esta es una pregunta genérica que siempre me he preguntado.

En general, ¿es intensivo para una CPU crear subprocesos que realizan bucles "aunque no sean verdaderos ..." o similares?

Por ejemplo, supongamos que hago:

// pseudo-code
new Thread(function() {
    while (!useHasDoneSomething) {
        // do nothing...
    }
    alert("you did something!");
}

Entonces, es solo un fragmento de código que se ejecuta en un hilo que espera que algo suceda.

Por alguna razón, imagino que esto presionaría a la CPU. Después de todo, aunque es solo un pequeño bucle, está volviendo a ejecutar el bucle en el instante en que se realiza un ciclo. ¿No significa esto que está pasando por el ciclo muchas veces por milisegundo? ¿... por nanosegundo?

El sistema operativo "manejará" el programa y los hilos, ¿verdad? Pero eso sigue siendo una gran atención para ejecutar un bucle. Si la CPU no tiene nada más que hacer, ¿no se centraría en ese bucle y consumiría todo el tiempo de inactividad ?

¿Qué pasa si creo 1000 hilos que hacen el mismo bucle? ¿Cómo podría afectar eso el rendimiento / ciclos de CPU?

Además, ¿es así como los eventos funcionan internamente? Cuando está 'escuchando' un evento en Java, .NET, Javascript, etc. (como presionar un botón o cambiar el tamaño de una ventana), ¿se ha creado un hilo que repite?

Rowan Freeman
fuente
1
¿Qué te dice el perfilador?
Arseni Mourzenko
2
Mi pregunta es genérica. No es tanto una cuestión de números sino más "¿Qué hay de malo en mi comprensión?"
Rowan Freeman
Entendido. +1 entonces.
Arseni Mourzenko

Respuestas:

12

En general, ¿es intensivo para una CPU crear subprocesos que realizan bucles "aunque no sean verdaderos ..." o similares?

Si. El uso de este ciclo se llama espera ocupada y se llama así por una razón. Estos bucles ocupados comprueban la condición tan a menudo y tan rápido como el procesador puede gestionarla, con el resultado de que, si permanece en el bucle el tiempo suficiente, la carga del procesador aumenta de manera confiable al 100%.

¿Qué pasa si creo 1000 hilos que hacen el mismo bucle? ¿Cómo podría afectar eso el rendimiento / ciclos de CPU?

Solo crea más trabajo para la CPU haciendo anotaciones.

Además, ¿es así como los eventos funcionan internamente? Cuando está 'escuchando' un evento en Java, .NET, Javascript, etc. (como presionar un botón o cambiar el tamaño de una ventana), ¿se ha creado un hilo que repite?

No. Los bucles ocupados son una forma de sondeo y también muy ineficiente. Los sistemas operativos tienen otros mecanismos para detectar que ha ocurrido un evento (por ejemplo, una interrupción o una llamada específica) y tienen mecanismos para permitir que un hilo lo espere sin consumir tiempo de CPU. Estos mecanismos también se utilizarán para implementar los mecanismos de eventos de lenguajes como Java.

Bart van Ingen Schenau
fuente
¡Gracias! ¿Qué pasa si duermes el hilo durante períodos cortos, tal vez 100 milisegundos, durante el ciclo? ¿Eso ralentizaría el hilo lo suficiente como para que los ciclos de la CPU no se desperdicien con tanta frecuencia y, por lo tanto, el rendimiento se recupere?
Rowan Freeman
1
@RowanFreeman: Disminuye la carga en el procesador, pero aún será más alto que simplemente esperar a que el sistema operativo le diga que X ha sucedido.
Bart van Ingen Schenau
9

Tu instinto es correcto. Ocupado esperando así se describe como

El spinning puede ser una estrategia válida en ciertas circunstancias, especialmente en la implementación de spinlocks dentro de los sistemas operativos diseñados para ejecutarse en sistemas SMP. Sin embargo, en general, el giro se considera un antipatrón y debe evitarse, ya que el tiempo del procesador que podría usarse para ejecutar una tarea diferente se desperdicia en una actividad inútil.

En cambio, debe considerar una primitiva de control de concurrencia que permita que el hilo realmente quede inactivo hasta que tenga un trabajo útil que hacer, por ejemplo, un semáforo o una variable de condición :

Para muchas aplicaciones, la exclusión mutua no es suficiente. Los subprocesos que intentan una operación pueden necesitar esperar hasta que se cumpla alguna condición. Un bucle de espera ocupado, como

while not( condition ) do 
   // nothing
end

no funcionará, ya que la exclusión mutua evitará que cualquier otro hilo ingrese al monitor para hacer que la condición sea verdadera. Existen otras "soluciones". Como tener un bucle que desbloquea el monitor, espera una cierta cantidad, bloquea el monitor y verifica la condición P. Teóricamente, funciona y no se bloqueará, pero surgen problemas. Es difícil decidir una cantidad de tiempo de espera adecuada, demasiado pequeña y el hilo acaparará la CPU, demasiado grande y aparentemente no responderá. Lo que se necesita es una forma de señalar el hilo cuando la condición P es verdadera (o podría ser verdadera). La solución son las variables de condición. Conceptualmente, una variable de condición es una cola de subprocesos, asociada con un monitor, en la que un subproceso puede esperar a que se cumpla alguna condición. Por lo tanto, cada variable de condición está asociada con una aserción. Mientras un subproceso está esperando una variable de condición, no se considera que ese subproceso ocupe el monitor, por lo que otros subprocesos pueden ingresar al monitor para cambiar su estado. En la mayoría de los tipos de monitores, estos otros subprocesos pueden indicar la variable de condición para indicar que la afirmación es verdadera en el estado actual.

Steven Schlansker
fuente
Entonces, ¿está ocupado esperando mucho éxito? ¿Un solo bucle (aunque dispara constantemente) tiene algún problema?
Rowan Freeman
1
@RowanFreeman lo es. La espera ocupada, como sugiere el texto, sigue grabando ciclos de CPU en instrucciones inútiles ( es decir , repitiendo if (!useHasDoneSomething)una y otra vez, tan rápido como sea posible). Incluso si no le importa en su programa, desperdicia tiempo que otros programas podrían usar para ejecutarse. Pero incluso dentro de su programa, un camarero ocupado pierde tiempo que podría asignarse a algún subproceso de trabajo (en caso de que no haya suficientes núcleos disponibles para que todos los subprocesos se ejecuten simultáneamente).
Afsantos
2
@afsantos Hay usos válidos para la espera ocupada: las alternativas generalmente implican desprogramar su hilo y reprogramarlo más tarde. Si sabe que no realizará un ciclo durante más de unos pocos ciclos de CPU, puede ser mucho más eficiente esperar ocupado que permitir un cambio de contexto.
Assylias
1
@assylias De hecho, un cambio de contexto puede ser más un golpe de rendimiento, si se sabe que el tiempo de espera es muy corto. Sin embargo, desde mi experiencia, las esperas ocupadas son inapropiadas la mayoría de las veces. El OP tendría que evaluar su caso individual, para ver si vale la pena o no.
Afsantos
2

Los hilos deben esperar los eventos entrantes, no los cambios variables.

Los eventos entrantes son semáforos disponibles, colas de mensajes que no están vacías o transcurrido el tiempo:

semGet()
msqRead()
sleep()

Desde el punto de vista del subproceso, estas llamadas de función están bloqueando: el subproceso espera hasta que se produce el evento, dejando la carga de la CPU a otros subprocesos.

Desde el punto de vista del sistema, el hilo está marcado como 'Esperando evento' y no se programará mientras el evento no haya llegado.

Sobre los eventos de hardware, se manejan a través de interrupciones que son señales eléctricas a la CPU y que desencadenan la ejecución de ISR (rutinas de servicio de interrupción), cuya función es producir un evento de software en semáforos, colas de mensajes o tiempo.

Mouviciel
fuente
0

La //do nothing parte interior mientras la condición en el escenario normal es ESPERAR en algún semáforo, o en otros términos SUEÑO. Duerme hasta que alguna interrupción te haya despertado. Y, por lo tanto, el subproceso va en "estado de suspensión" o simplemente digamos "estado de no ejecución". Solo los procesos que están en estado de ejecución consumen CPU. El proceso de estado de suspensión no consumirá CPU. Pueden estar consumiendo memoria, pero esa memoria será intercambiada internamente por el sistema de memoria virtual. Entonces, incluso si crea 1000 hilos de este tipo, no representarán una gran amenaza para su sistema.

Manoj R
fuente