Domanda

Sto scrivendo un'applicazione job-scheduling in Ruby per il mio lavoro (principalmente per spostare i file utilizzando vari protocolli ad una determinata frequenza)

Il mio ciclo principale appare così:

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

Si sta lavorando come un fascino, ma non sono proprio sicuro se è abbastanza sicuro come l'applicazione potrebbe funzionare su un server con CPU-intensive software in esecuzione.

C'è un altro modo di fare la stessa cosa, o si sleep() abbastanza sicuro nel mio caso?

È stato utile?

Soluzione

Utilizzando il sonno è probabilmente bene per le cose rapido e sporco. Ma per le cose che hanno bisogno di un po 'di più la robustezza e l'affidabilità suggerisco che il sonno è il male :) Il problema con il sonno è che il filo è (sto supponendo di Windows qui ...) è veramente addormentato - lo scheduler non verrà eseguito il thread fino a qualche tempo dopo l'intervallo di sonno è passato.

Durante questo tempo, il thread non svegliarsi per qualche cosa. Ciò significa che non può essere cancellato, o svegliarsi per elaborare qualche tipo di evento. Naturalmente, il processo può essere ucciso, ma che non dà il filo di sonno la possibilità di svegliarsi e pulito nulla fino.

Non ho familiarità con Ruby, ma suppongo che ha un qualche tipo di struttura per l'attesa su cose più. Se è possibile, suggerisco che invece di utilizzare il sonno, si waint su due cose \

  1. Un timer che risveglia il filo periodicamente per fare il suo lavoro.
  2. Un evento che è impostato quando processo deve cancellare o piuttosto (trapping control-C, per esempio).

Sarebbe ancora meglio se c'è un qualche tipo di evento che può essere utilizzato per segnalare la necessità di fare un lavoro. Ciò eviterebbe il polling su un timer. Questo porta generalmente ad abbassare l'utilizzo delle risorse e di un sistema più reattivo.

Altri suggerimenti

Ogni volta che sento il bisogno di bloccare, io uso un ciclo di eventi; di solito libev. Ecco un rubino vincolante:

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

In sostanza, sleep è perfettamente bene se si desidera che il processo di andare a dormire senza avere nient'altro in corso in background. Se mai voglia di fare altre cose, anche se, come il sonno e anche aspettare per le connessioni TCP o un filehandle per diventare leggibili, allora si sta andando ad avere per utilizzare un ciclo di eventi. Quindi, perché non basta usare uno all'inizio?

Il flusso della vostra applicazione sarà:

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

Quando si vuole fare altre cose, basta creare l'osservatore, e succede per voi. (I posti di lavoro che si sta eseguendo anche possibile creare osservatori.)

Se non avete bisogno di un intervallo esatto, allora ha senso per me. Se avete bisogno di essere risvegliato a orari regolari senza deriva, probabilmente avrete bisogno di utilizzare una sorta di timer esterno. Ma quando si è addormentato, non si sta usando le risorse della CPU. E 'l'interruttore compito che è costoso.

Mentre sleep(timeout) è perfettamente appropriato per alcuni disegni, c'è un avvertimento importante da tenere a mente.

Rubino installa gestori di segnale con SA_RESTART (vedi qui ), il che significa che il vostro sleep (o select(nil, nil, nil, timeout) equivalente) non possono essere facilmente interrotte. Il tuo gestore di segnale scatterà, ma il programma andrà a destra torna a sleep. Questo può essere scomodo se si voleva reagire tempestivamente a, diciamo, un SIGTERM.

Si consideri che ...

#! /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."

... ci vogliono circa 30 secondi per eseguire, piuttosto che 2.

Per risolvere il problema, si potrebbe invece generare un'eccezione nel vostro gestore di segnale, che interrompe il sonno (o qualsiasi altra cosa!) Di cui sopra. Si potrebbe anche passare a un ciclo select-based e utilizzare una variante del href="http://cr.yp.to/docs/selfpipe.html" rel="nofollow noreferrer"> trucco auto-pipe di svegliarsi "presto" alla ricezione di un segnale. Come altri hanno fatto notare, le librerie di eventi completamente presenti sono disponibili, anche.

E 'abitudine usa CPU mentre si sta dormendo, ma se si dorme a lungo sarei più preoccupato dalla corsa rubino interprete alzando la memoria mentre non stava facendo nulla. Questo non è così grande di un affare tho.

scroll top