2009-07-24 10 views
8

Estoy escribiendo una aplicación de trabajo de programación en Ruby para mi trabajo (principalmente para mover archivos a través de varios protocolos a una frecuencia dada)es dormir() una buena idea para el bucle principal de una aplicación de trabajo de programación

Mi bucle principal se ve así:

while true do 
    # some code to launch the proper job 
    sleep CONFIG["interval"] 
end 

está funcionando a las mil maravillas, pero no estoy muy seguro si es lo suficientemente seguro como la aplicación pueda ejecutarse en un servidor con el correr de software intensivo de la CPU.

¿Hay alguna otra manera de hacer lo mismo, o es sleep() lo suficientemente seguro en mi caso?

Respuesta

5

Usar el modo de suspensión probablemente sea correcto para cosas sucias y rápidas. Pero para las cosas que necesitan un poco más de robustez o confiabilidad sugiero que dormir es malo :) El problema con dormir es que el hilo es (estoy asumiendo que Windows aquí ...) está realmente dormido - el programador no ejecutará el hilo hasta algún tiempo después de que el intervalo de sueño haya pasado.

Durante este tiempo, el hilo no se activará por nada. Esto significa que no puede cancelarse o despertarse para procesar algún tipo de evento. Por supuesto, el proceso se puede matar, pero eso no le da al hilo de dormir la oportunidad de despertar y limpiar todo.

No estoy familiarizado con Ruby, pero supongo que tiene algún tipo de facilidad para esperar en varias cosas. Si puede, le sugiero que en lugar de utilizar el modo de suspensión, vacile en dos cosas \

  1. Un temporizador que activa el hilo periódicamente para hacer su trabajo.
  2. Un evento que se establece cuando el proceso necesita cancelar o bastante (atrapando control-C, por ejemplo).

Sería aún mejor si hay algún tipo de evento que pueda utilizarse para señalar la necesidad de realizar un trabajo. Esto evitaría el sondeo en un temporizador.Esto generalmente conduce a una menor utilización de recursos y un sistema más receptivo.

3

Si no necesita un intervalo exacto, entonces tiene sentido para mí. Si necesita despertarse a intervalos regulares sin deriva, es probable que desee utilizar algún tipo de temporizador externo. Pero cuando estás dormido, no estás usando recursos de la CPU. Es el cambio de tarea que es caro.

7

Cada vez que siento la necesidad de bloquear, utilizo un bucle de evento; usualmente libev. Aquí es un rubí unión:

http://rev.rubyforge.org/rdoc/

Básicamente, sleep está perfectamente bien si desea que su proceso de ir a dormir sin tener nada más en juego en el fondo. Sin embargo, si alguna vez quiere hacer otras cosas, como dormir y también esperar que las conexiones TCP o un manejador de archivos se vuelvan legibles, entonces tendrá que usar un bucle de eventos. Entonces, ¿por qué no usar uno al principio?

El flujo de su aplicación será:

main { 
    Timer->new(after => 0, every => 60 seconds, run => { <do your work> }) 
    loop(); 
} 

Cuando se quiere hacer otras cosas, que acaba de crear el observador, y sucede para usted. (Los trabajos que está ejecutando también pueden crear vigilantes).

+0

¿Cómo se rompe este ciclo si se cumple la condición? – Fadi

2

No utilizará la CPU mientras está durmiendo, pero si duerme durante mucho tiempo, me preocuparía más que el intérprete de ruby ​​ejecutando la memoria mientras no estaba está haciendo cualquier cosa Esto no es tan importante, sin embargo.

+0

Si entiendo correctamente, esto significa que usa recursos de memoria pero no recursos de CPU mientras duerme? –

3

Si bien sleep(timeout) es perfectamente apropiado para algunos diseños, hay una advertencia importante a tener en cuenta.

Rubí instala manejadores de señales con SA_RESTART (ver here), lo que significa que su sleep (o equivalente select(nil, nil, nil, timeout)) no puede fácilmente ser interrumpido. Su controlador de señal se activará, pero el programa volverá directamente al sleep. Esto puede ser un inconveniente si desea reaccionar a tiempo, digamos, a SIGTERM.

Considere que ...

#! /usr/bin/ruby 
Signal.trap("USR1") { puts "Hey, wake up!" } 
Process.fork() { sleep 2 and Process.kill("USR1", Process.ppid) } 
sleep 30 
puts "Zzz. I enjoyed my nap." 

... tardará unos 30 segundos para ejecutar, en lugar de 2.

Como solución alternativa, es posible que en lugar de lanzar una excepción en su manejador de señales, que interrumpiría el sueño (¡o cualquier otra cosa!) de arriba. También puede cambiar a un bucle basado en select y usar una variante del self-pipe trick para despertarse "temprano" al recibir una señal. Como otros han señalado, las bibliotecas de eventos con todas las funciones están disponibles también.

+1

Esto no es muy bonito, pero ¿sería suficiente hacer '10.times {sleep 1}'? Esto sería como dormir por 10 pero darle un tiempo máximo para responder de 1 segundo. –

+0

@Brian: sí, funcionaría. Sí, no es bonita. – pilcrow

Cuestiones relacionadas