Ich schreibe eine Job-Scheduling-App in Ruby für meine Arbeit (hauptsächlich um Dateien mit verschiedenen Protokollen auf einer bestimmten Frequenz zu verschieben)
Meine Hauptschleife sieht so aus:
%Vor%Es funktioniert wie ein Zauber, aber ich bin mir nicht sicher, ob es sicher genug ist, da die Anwendung möglicherweise auf einem Server läuft, auf dem cpu-intensive Software läuft.
Gibt es eine andere Möglichkeit, dasselbe zu tun, oder ist sleep()
in meinem Fall sicher genug?
Schlaf ist wahrscheinlich in Ordnung für schnelle und schmutzige Dinge. Aber für Dinge, die ein wenig mehr Robustheit oder Zuverlässigkeit benötigen, schlage ich vor, dass Schlaf böse ist :) Das Problem mit dem Schlafen ist, dass der Thread (Ich nehme an, Windows hier ...) ist wirklich eingeschlafen - der Scheduler wird den Thread nicht ausführen bis einige Zeit nach dem Schlaf-Intervall vergangen ist.
Während dieser Zeit wird der Thread für nichts aufwachen. Dies bedeutet, dass es nicht abgebrochen werden kann oder aufwacht, um irgendeine Art von Ereignis zu verarbeiten. Natürlich kann der Prozess abgebrochen werden, aber das gibt dem schlafenden Thread keine Gelegenheit, aufzuwachen und alles zu säubern.
Ich bin mit Ruby nicht vertraut, aber ich nehme an, dass es eine Art von Möglichkeit gibt, auf mehrere Dinge zu warten. Wenn Sie können, schlage ich vor, dass Sie anstelle von Schlaf, zwei Dinge waint \ r \ n \
Es wäre sogar noch besser, wenn es irgendeine Art von Ereignis gibt, das dazu benutzt werden könnte, die Notwendigkeit zu signalisieren, Arbeit zu tun. Dies würde das Abrufen eines Zeitgebers vermeiden. Dies führt im Allgemeinen zu einer geringeren Ressourcennutzung und einem reaktionsfähigeren System.
Immer wenn ich das Bedürfnis verspüre zu blockieren, benutze ich eine Ereignisschleife; normalerweise libev. Hier ist eine Ruby-Bindung:
Grundsätzlich ist sleep
völlig in Ordnung, wenn Sie möchten, dass Ihr Prozess in den Ruhezustand versetzt wird, ohne dass etwas anderes im Hintergrund läuft. Wenn Sie jedoch andere Dinge tun möchten, wie zum Beispiel den Ruhezustand und warten, bis TCP-Verbindungen oder ein Dateihandle lesbar werden, dann müssen Sie eine Ereignisschleife verwenden. Also, warum nicht einfach einen zu Beginn benutzen?
Der Fluss Ihrer Anwendung wird sein:
%Vor%Wenn Sie andere Dinge tun wollen, erstellen Sie einfach den Beobachter, und es passiert für Sie. (Die Jobs, die Sie ausführen, können auch Watcher erstellen.)
Wenn Sie kein genaues Intervall brauchen, macht es für mich Sinn. Wenn Sie zu regelmäßigen Zeiten ohne Drift geweckt werden müssen, möchten Sie wahrscheinlich einen externen Timer verwenden. Aber wenn Sie schlafen, verwenden Sie keine CPU-Ressourcen. Es ist der Task-Schalter, der teuer ist.
Obwohl sleep(timeout)
für einige Designs perfekt geeignet ist, gibt es einen wichtigen Vorbehalt, den man beachten sollte.
Ruby installiert Signalhandler mit SA_RESTART
(siehe hier ), was bedeutet, dass dein sleep
(oder äquivalent select(nil, nil, nil, timeout)
) kann nicht einfach unterbrochen werden. Dein Signal-Handler wird ausgelöst, aber das Programm wird direkt zu sleep
zurückkehren. Dies kann unpraktisch sein, wenn Sie z. B. auf SIGTERM
rechtzeitig reagieren möchten.
Bedenken Sie das ...
%Vor%... dauert etwa 30 Sekunden und nicht 2.
Als Workaround können Sie stattdessen eine Ausnahme in Ihrem Signal-Handler auslösen, die den Schlaf (oder etwas anderes!) oben unterbrechen würde. Sie können auch zu einer select
-basierten Schleife wechseln und eine Variante des Self-Pipe-Tricks verwenden, um aufzuwachen auf "früh" nach Empfang eines Signals. Andere haben darauf hingewiesen, dass auch voll funktionsfähige Ereignisbibliotheken verfügbar sind.
Es wird nicht die CPU verwenden, während es schläft, aber wenn Sie für eine lange Zeit schlafen, würde ich mehr besorgt sein, dass der running Ruby Interpreter Speicher hält, während es nichts getan hat. Das ist keine große Sache, tho.
Tags und Links ruby job-scheduling multitasking