Le sommeil est () une bonne idée pour la boucle principale d'une application-horaire de l'emploi

StackOverflow https://stackoverflow.com/questions/1179301

Question

J'écris une application-horaire du travail en Ruby pour mon travail (principalement pour déplacer des fichiers en utilisant différents protocoles à une fréquence donnée)

Ma boucle principale ressemble à ceci:

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

Il fonctionne comme un charme, mais je ne suis pas vraiment sûr si elle est assez sûr que l'application peut fonctionner sur un serveur avec un logiciel cpu-intensive fonctionnement.

Y at-il une autre façon de faire la même chose, ou est sleep() assez sûr dans mon cas?

Était-ce utile?

La solution

Utilisation de sommeil est OK probable pour les choses rapides et sales. Mais pour des choses qui ont besoin d'un peu plus de robustesse ou la fiabilité, je suggère que le sommeil est le mal :) Le problème avec le sommeil est que le fil est (je suppose ici de Windows ...) est vraiment endormi - le programmateur ne fonctionne pas le fil jusqu'à un certain temps après intervalle de sommeil est passé.

Pendant ce temps, le fil ne se réveillera pas pour quoi que ce soit. Cela signifie qu'il ne peut pas être annulée, ou se réveiller pour traiter une sorte d'événement. Bien sûr, le processus peut être tué, mais cela ne donne pas le fil de dormir l'occasion de se réveiller et tout nettoyer.

Je ne suis pas familier avec Ruby, mais je suppose qu'il a une sorte de facilité d'attente sur plusieurs choses. Si vous le pouvez, je vous suggère qu'au lieu d'utiliser le sommeil, vous Waint sur deux choses \

  1. Une minuterie qui réveille le fil périodiquement pour faire son travail.
  2. Un événement qui est réglé quand il processus doit annuler ou tout à fait (contrôle-C par exemple le piégeage).

Il serait encore mieux s'il y a une sorte d'événement qui peut être utilisé pour signaler la nécessité de faire un travail. Cela éviterait l'interrogation sur une minuterie. Cela conduit généralement à réduire l'utilisation des ressources et un système plus réactif.

Autres conseils

Chaque fois que je ressens le besoin de bloquer, j'utiliser une boucle d'événement; habituellement libev. Voici un binding Ruby:

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

En fait, sleep est parfaitement bien si vous voulez que votre processus d'aller dormir sans avoir quoi que ce soit d'autre se passe en arrière-plan. Si jamais vous voulez faire d'autres choses, mais, comme le sommeil et aussi attendre les connexions TCP ou un descripteur de fichier pour devenir lisible, alors vous allez devoir utiliser une boucle d'événements. Alors, pourquoi ne pas simplement utiliser une au début?

Le flux de votre application sera:

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

Si vous voulez faire d'autres choses, vous créez juste le veilleur, et il arrive pour vous. (Les emplois que vous exécutez peuvent également créer des observateurs.)

Si vous n'avez pas besoin d'intervalle exact, alors il est logique pour moi. Si vous avez besoin d'être réveillé à des heures régulières sans dérive, vous voulez probablement utiliser une sorte de minuterie externe. Mais quand vous êtes endormi, vous n'êtes pas en utilisant les ressources CPU. Il est le commutateur de tâche qui est cher.

Alors que sleep(timeout) est parfaitement approprié pour certains modèles, il y a une mise en garde importante à garder à l'esprit.

Ruby installe un gestionnaire de signal avec SA_RESTART (voir ), ce qui signifie que votre sleep (ou équivalent select(nil, nil, nil, timeout)) ne peuvent pas facilement être interrompus. Votre gestionnaire de signal se déclenche, mais le programme sera de retour à sleep. Cela peut être gênant si vous vouliez réagir en temps opportun, disons, un SIGTERM.

Considérez 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."

... prendra environ 30 secondes pour exécuter, plutôt que 2.

Pour contourner ce problème, vous pourriez jeter à la place une exception dans votre gestionnaire de signaux, qui interromprait le sommeil (ou quoi que ce soit d'autre!) Ci-dessus. Vous pouvez également passer à une boucle à base select et utiliser une variante du trick auto-pipe de se réveiller « tôt » à la réception d'un signal. Comme d'autres l'ont souligné, les bibliothèques d'événements entièrement en vedette sont également disponibles.

Il utilise l'habitude CPU pendant qu'il dort, mais si vous dormez pendant longtemps je serais plus préoccupé de l'interpréteur Ruby en cours d'exécution tenant de la mémoire alors qu'il ne faisait rien. Ce n'est pas un gros tho affaire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top