Frage
Ich möchte in der Lage sein, über einen langen Zeitraum genau jede Sekunde einen UNIX-Befehl auszuführen .
Ich brauche eine Lösung, die nach einer bestimmten Zeit nicht zurückbleibt, weil der Befehl selbst für die Ausführung Zeit benötigt. sleep , watch und ein bestimmtes Python-Skript haben mich diesbezüglich alle im Stich gelassen.
Auf den Mikrocontrollern wie http://Arduino.cc würde ich das durch Hardware Clock Interrupts machen. Ich würde gerne wissen, ob es eine ähnliche zeitgenaue Shell-Skriptlösung gibt. Alle Lösungen, die ich in StackExchange.com gefunden habe, führten zu einer spürbaren Zeitverzögerung, wenn sie über Stunden ausgeführt wurden. Details siehe unten.
Praktischer Zweck / Anwendung
Ich möchte testen, ob meine Netzwerkverbindung ständig besteht, indem ich nc
alle 1 Sekunde Zeitstempel über (netcat) sende .
Absender:
precise-timestamp-generator | tee netcat-sender.txt | nc $receiver $port
Empfänger:
nc -l -p $port > netcat-receiver.txt
Vergleichen Sie nach Abschluss die beiden Protokolle:
diff netcat-sender.txt netcat-receiver.txt
Die Unterschiede wären die nicht übertragenen Zeitstempel. Daraus würde ich wissen, wann mein LAN / WAN / ISP Probleme macht.
Lösung SCHLAFEN
while [ true ]; do date "+%Y-%m-%d %H:%M:%S" ; sleep 1; done | tee timelog-sleep.txt
Erhält einen bestimmten Versatz im Laufe der Zeit, da der Befehl innerhalb der Schleife auch etwas Zeit benötigt.
Präzision
cat timelog-sleep.txt
2012-07-16 00:45:16
[...]
2012-07-16 10:20:36
Verstrichene Sekunden: 34520
wc -l timelog-sleep.txt
Zeilen in der Datei: 34243
Präzision zusammengefasst:
- 34520-34243 = 277 Zeitprobleme
- 34520/34243 = 1,008 = 0,8% Rabatt
Lösung PYTHON WIEDERHOLEN
Gefunden bei: Wiederholen Sie einen Unix-Befehl alle x Sekunden für immer
repeat.py 1 "date '+%Y-%m-%d %H:%M:%S'" >> timelog-repeat-py.txt
Soll den Zeitversatz vermeiden, tut dies aber nicht.
Präzision
wc -l timelog-repeat-py.txt
2012-07-16 13:42:44
[...]
2012-07-16 16:45:24
Verstrichene Sekunden: 10960
wc -l timelog-repeat-py.txt
Zeilen in der Datei: 10859
Präzision zusammengefasst:
- 10960-10859 = 101 Zeitprobleme
- 10960/10859 = 1,009 = 0,9% Rabatt
Lösung UHR
watch -n 1 "date '+%Y-%m-%d %H:%M:%S' >> ~/Desktop/timelog-watch.txt"
Präzision
wc -l timelog-watch.txt
2012-07-16 11:04:08
[...]
2012-07-16 13:25:47
Verstrichene Sekunden: 8499
wc -l timelog-watch.txt
Zeilen in der Datei: 8366
Präzision zusammengefasst:
- 8499-8366 = 133 Zeitprobleme.
- 8499/8366 = 1,016 = 1,6% Rabatt.
nice
den Prozess schläfst?Antworten:
Wie funktioniert dieses Perl-Skript, das ich gerade erstellt habe?
Verwenden:
perl timer.pl 1 date '+%Y-%m-%d %H:%M:%S'
Es wurde 45 Minuten ohne einen einzigen Sprung ausgeführt, und ich vermute, dass dies so bleibt, es sei denn, a) die Systemlast wird so hoch, dass fork () länger als eine Sekunde dauert, oder b) eine Schaltsekunde eingefügt wird.
Es kann jedoch nicht garantiert werden, dass der Befehl in exakten Sekundenintervallen ausgeführt wird, da ein gewisser Overhead vorliegt, aber ich bezweifle, dass dies viel schlimmer ist als eine Interrupt-basierte Lösung.
Ich habe es ungefähr eine Stunde lang mit
date +%N
(Nanosekunden, GNU-Erweiterung) ausgeführt und einige Statistiken dazu erstellt. Die größte Verzögerung betrug 1 155 Mikrosekunden. Durchschnitt (arithmetisches Mittel) 216 µs, Median 219 µs, Standardabweichung 42 µs. Es lief in 95% der Fälle schneller als 270 µs. Ich glaube nicht, dass man es schlagen kann, außer mit einem C-Programm.quelle
GNU date
mit+%N
und nach nur 3 Minuten warf er diesen Fehler:Time::HiRes::sleep(-0.00615549): negative time not invented yet at ~/bin/repeat.pl line 23.
Zeile 23 in meinem gespeicherten Skript:sleep $start - time();
Mit der POSIX-
ualarm()
Funktion können Sie festlegen, dass der Kernel Ihren Prozess regelmäßig mit einer Genauigkeit von Mikrosekunden signalisiert.Erstellen Sie ein einfaches Programm:
Kompilieren
Dann hängen Sie es wie folgt an das an, was Sie in regelmäßigen Abständen tun müssen:
quelle
-std=c99
, werden Sie nicht die Warnung über die fehlende Rückkehr bekommen. Ansonsten sollten Sie nichts Besonderes brauchen. Haben Sie eine zusätzliche Null falsch eingegeben?strace ./tick
zeigt Ihnen, was es aus einer syscall Perspektive tutHast du es
watch
mit dem Parameter versucht--precise
?Von der Manpage:
Der Parameter ist jedoch möglicherweise auf Ihrem System nicht verfügbar.
Sie sollten auch überlegen, was passieren soll, wenn die Ausführung Ihres Programms länger als eine Sekunde dauert. Soll die nächste geplante Ausführung übersprungen oder zu spät ausgeführt werden?
Update : Ich habe das Skript einige Zeit lang ausgeführt und es hat keinen einzigen Schritt verloren:
Update: Die
--precise
Flagge ist eine Debian-Erweiterung, der Patch ist jedoch recht einfach: http://patch-tracker.debian.org/patch/series/view/procps/1:3.2.8-9squeeze1/watch_precision_time.patchquelle
watch
unterstützt diese Option? Es war auf keiner der Maschinen, die ich überprüft habe.--precise
. Dies ist ein Debian-Zusatz (3.2.8-9, watch_precision_time.patch)2012-07-24 07:20:21.864818595 2012-07-24 07:20:22.467458430 2012-07-24 07:20:23.068575669 2012-07-24 07:20:23.968415439
Das Echtzeit-Zeug (Kernel usw.) ist nicht ohne Grund da draußen!crontab
hat eine Auflösung von 1 Minute. Wenn es Ihnen nichts ausmacht, dass sich die Verzögerungszeit in dieser Minute erhöht und dann in der nächsten Minute zurückgesetzt wird, könnte diese Grundidee funktionieren:Beachten Sie, dass
script.sh
auch im Hintergrund ausgeführt wird. Dies sollte helfen, die Verzögerung zu minimieren, die sich bei jeder Iteration der Schleife ansammelt.Abhängig davon, wie viel Verzögerung
sleep
erzeugt wird, besteht jedoch die Möglichkeit, dass sich die Sekunde 59 mit der Sekunde 0 der nächsten Minute überschneidet.BEARBEITEN , um einige Ergebnisse im gleichen Format wie in der Frage zu werfen:
1 Stunde 52 Minuten = 6720 Sekunden
0 Zeitprobleme, 0% Rabatt. Jede Zeitansammlung wird jede Minute zurückgesetzt.
quelle
cron
auf die Sekunde genau ist, aber das ist im Allgemeinen nicht der Fall .Ihr Problem ist, dass Sie nach dem Ausführen Ihres Programms eine bestimmte Zeit lang schlafen, ohne die Zeit zu berücksichtigen, die seit dem letzten Schlafen vergangen ist .
Sie können dies mit Bash oder einer anderen Programmiersprache tun. Der Schlüssel besteht jedoch darin, anhand der Uhr zu bestimmen, wie lange der nächste Ruhezustand geplant werden soll. Überprüfen Sie vor dem Schlafengehen die Uhr, sehen Sie nach, wie viel Zeit Ihnen noch zur Verfügung steht, und machen Sie den Unterschied aus.
Aufgrund von Kompromissen bei der Prozessplanung kann nicht garantiert werden, dass Sie genau zur richtigen Zeit aufwachen. Sie sollten jedoch ziemlich nah dran sein (innerhalb weniger ms (entladen) oder innerhalb weniger hundert ms (unter Last)). Und Sie werden mit der Zeit keine Fehler ansammeln, da Sie jedes Mal bei jedem Schlafzyklus neu synchronisieren und alle angesammelten Fehler entfernen.
Wenn Sie genau auf die Uhr ticken müssen, suchen Sie ein Echtzeit-Betriebssystem , das genau für diesen Zweck entwickelt wurde.
quelle
date +%S.%N
, um die Anzahl der Sekunden mit einer Genauigkeit von weniger als einer Sekunde abzurufen undusleep
mit einer Genauigkeit von weniger als einer Sekunde zu schlafen, aber danach ist es nur noch eine Frage der Mathematik.Ich habe es immer aufgegeben, etwas genau im Intervall laufen zu lassen. Ich denke, Sie müssen ein C-Programm schreiben und sehr sorgfältig darauf achten, den Teil des 1-Sekunden-Intervalls mit Ihrem eigenen Code nicht zu überschreiten. Wahrscheinlich müssen Sie Threading oder mehrere miteinander kommunizierende Prozesse verwenden, damit dies funktioniert. Achten Sie darauf, dass der Zeitaufwand für das Starten von Threads oder Prozessen nicht zunimmt.
Eine Referenz, die für 1993 relevant zu sein scheint: Ein zufälliger Abtasttakt für die CPU-Auslastungsschätzung und das Code-Profiling Schauen Sie sich den Anhang "Quellcode des Gegners" an, um zu sehen, wie genau die Zeitintervalle gemessen und "aufgewacht" wurden. ihr Programm genau zur richtigen Zeit. Da der Code 19 Jahre alt ist, wird er wahrscheinlich nicht direkt oder einfach portiert, aber wenn Sie ihn lesen und versuchen, ihn zu verstehen, leiten die Prinzipien möglicherweise Ihren Code.
BEARBEITEN: Eine weitere Referenz gefunden, die hilfreich sein könnte: Auswirkungen der Taktauflösung auf die Planung interaktiver und weicher Echtzeitprozesse. Diese sollte Ihnen mit theoretischen Hintergründen weiterhelfen.
quelle
Schauen Sie sich nanosleep () an (von http://linux.about.com/library/cmd/blcmdl2_nanosleep.htm ). Anstatt das Programm für 1 Sekunde in den Ruhezustand zu versetzen, sollten Sie es für 1 Sekunde in den Ruhezustand versetzen. Sie erhalten eine viel bessere Auflösung.
quelle
sleep
, dhsleep 0.99
. Das Problem ist, dass die Zeit, die zum Ausführen benötigt wird, nicht konstant ist, auch wenn der Mittelwert über die Zeit schwanken kann.Versuchen Sie, Ihren Befehl im Hintergrund auszuführen, damit das Loop-Timing nicht so stark beeinflusst wird. Aber auch das reicht nicht aus, wenn Sie über einen längeren Zeitraum keine Akkumulation wünschen, da mit ihm sicherlich ein paar Millisekunden Kosten verbunden sind.
Das ist wahrscheinlich besser, aber wahrscheinlich immer noch nicht gut genug:
Auf meinem Computer ergaben sich 2 Fehler in 20 Minuten oder 0,1 pro Minute, was ungefähr einer fünffachen Verbesserung gegenüber Ihrem Lauf entspricht.
quelle
sleep 1
ist, dass es garantiert mindestens eine Sekunde schläft - niemals weniger. Daher akkumuliert sich der Fehler.Hässlich aber es funktioniert. Sie sollten wahrscheinlich das Design Ihres Programms überdenken, wenn Sie eine solche Schleife benötigen. Grundsätzlich wird überprüft, ob die aktuelle ganze Sekunde mit der zuvor überprüften Sekunde übereinstimmt, und die Anzahl der Nanosekunden seit dem Wechsel der Sekunde ausgegeben. Die Genauigkeit wird durch den Schlaf beeinflusst .001.
Die Genauigkeit ist in Millisekunden angegeben, sofern die "Nutzlast"
date "+%N nanoseconds late"
nicht länger als knapp eine Sekunde dauert. Sie können die CPU-Auslastung senken, indem Sie den Ruhezustand verlängern, oder wenn es Ihnen wirklich nichts ausmacht, ersetzen Sie einfach den Ruhezustand-Befehl durchtrue
.Dies ist eine schlechte Praxis, da Sie im Grunde genommen eine CPU-Abfrage für ein Ereignis durchführen und CPU-Zyklen verschwenden. Sie möchten wahrscheinlich eine Verbindung zu einem Timer-Interrupt herstellen (nicht über Bash möglich) oder dedizierte Hardware wie einen Mikrocontroller verwenden. Ein PC und sein Betriebssystem sind nicht für eine hohe Zeitgenauigkeit ausgelegt.
quelle
Eine andere Methode wäre, eine Unterbrechung in einer Schleife zu verwenden und SIGCONT von einem genauen externen Programm aus zu senden. Das Senden eines Signals ist sehr einfach und hat viel weniger Latenz als das Ausführen von etwas. Sie können auch eine Reihe von Befehlen mit dem Befehl "at" in die Warteschlange stellen. Kaum jemand verwendet mehr "at". Ich bin mir nicht sicher, wie genau es ist.
Wenn Präzision von entscheidender Bedeutung ist und Sie dies ernst nehmen möchten, klingt dies wie eine Anwendung, bei der Sie normalerweise RTOS verwenden, was unter Linux mit RT-Preempt-gepatchtem Kernel möglich ist und Ihnen die Präzision und ein gewisses Maß an Genauigkeit verleiht Interrupt-Kontrolle, aber es kann mehr Mühe geben, als es wert ist.
https://rt.wiki.kernel.org/index.php/RT_PREEMPT_HOWTO
Xenomai kann ebenfalls hilfreich sein, da es sich um eine vollständige RTOS-Implementierung handelt und für x86 und x86_64 portiert ist, aber einige Programmierungen erforderlich sind.
http://www.xenomai.org/index.php/Main_Page
quelle
Mit
ksh93
(welches einen Fließkomma$SECONDS
und ein eingebautes hatsleep
)Dasselbe Skript funktioniert
zsh
auch, ruft jedoch densleep
Befehl Ihres Systems auf .zsh
hat einezselect
eingebaute, aber nur mit 1/100 Auflösung.quelle
Ich würde mit einem kleinen C-Programm gehen:
Dieses Programm erwartet, dass das Programm den vollständigen Pfad als erstes Argument aufruft und alle verbleibenden Argumente weitergibt. Es wird nicht auf den Abschluss des Befehls warten, sodass mehrere Instanzen problemlos gestartet werden können.
Außerdem ist der Codierungsstil hier wirklich schlampig, und es wird eine Reihe von Annahmen getroffen, die möglicherweise von den geltenden Standards garantiert werden oder nicht, dh, die Qualität dieses Codes ist "funktioniert für mich".
Dieses Programm erhält etwas längere oder kürzere Intervalle, wenn die Uhr über NTP oder manuell eingestellt wird. Sollte das Programm damit umgehen, bietet POSIX an,
timer_create(CLOCK_MONOTONIC, ...)
was davon nicht betroffen ist.quelle
Sie sollten die aktuelle Uhrzeit verfolgen und mit der Startzeit vergleichen. Sie schlafen also für jede Iteration eine berechnete Menge an Zeit, keine feste Menge. Auf diese Weise sammeln sich keine Timing-Fehler an und verschieben sich von Ihrem Standort weg, da Sie Ihre Timings für jede Schleife von Anfang an auf die absolute Zeit zurücksetzen.
Außerdem kehren einige Schlaffunktionen bei einer Unterbrechung vorzeitig zurück. In diesem Fall müssen Sie Ihre Schlafmethode erneut aufrufen, bis die gesamte Zeit verstrichen ist.
quelle
Hier ist ein Bash-Skript, das sehr genau ist. Für die Mikrosekundengenauigkeit wird der Ruhezustand verwendet.
http://wiki.junkemailfilter.com/index.php/How_to_run_a_Linux_script_every_few_seconds_under_cron
Es gibt dort 3 Scrips. Schau dir den unten an. Kann bis zu 2400 Ausführungen pro Minute mit angemessener Genauigkeit ausführen. Und es ist ganz einfach.
quelle
Dieser kann mindestens 100 Mal pro Sekunde mit sehr genauer Auflösung ausgeführt werden.
Das Vorhandensein des Verzeichnisses der Anzahl der Schleifen pro Minute erstellt den Zeitplan. Diese Version unterstützt Mikrosekundenauflösung, vorausgesetzt, Ihr Computer kann damit umgehen. Die Anzahl der Ausführungen pro Minute muss nicht durch 60 teilbar sein und ist auch nicht auf 60 begrenzt. Ich habe es auf 6000 getestet und es funktioniert.
Diese Version kann im Verzeichnis /etc/init.d installiert und als Dienst ausgeführt werden.
quelle