Ich führe diese Schleife aus, um einige Dinge jede Sekunde zu überprüfen und auszudrucken. Da die Berechnungen jedoch einige Hundert Millisekunden dauern, überspringt die Druckzeit manchmal eine Sekunde.
Gibt es eine Möglichkeit, eine solche Schleife zu schreiben, bei der ich garantiert jede Sekunde einen Ausdruck bekomme? (Vorausgesetzt natürlich, dass die Berechnungen in der Schleife weniger als eine Sekunde dauern :))
while true; do
TIME=$(date +%H:%M:%S)
# some calculations which take a few hundred milliseconds
FOO=...
BAR=...
printf '%s %s %s\n' $TIME $FOO $BAR
sleep 1
done
bash
timestamps
sleep
Forthrin
quelle
quelle
sched(7)
API aufruft (POSIX: siehe<sched.h>
und von dort verknüpfte Seiten), können Sie im Grunde keine Echtzeitgarantien dieser Form haben.Antworten:
Um dem ursprünglichen Code ein wenig näher zu kommen, mache ich Folgendes:
Dies ändert die Semantik ein wenig: Wenn Ihre Arbeit weniger als eine Sekunde gedauert hat, wartet sie einfach, bis die volle Sekunde verstrichen ist. Wenn Ihre Arbeit jedoch aus irgendeinem Grund länger als eine Sekunde dauert, werden nicht mehr Unterprozesse erzeugt, ohne dass dies zu Ende geht.
Ihre Inhalte werden also niemals parallel und nicht im Hintergrund ausgeführt, sodass auch Variablen wie erwartet funktionieren.
Beachten Sie, dass Sie, wenn Sie zusätzliche Hintergrundaufgaben starten, die
wait
Anweisung ändern müssen, um nur auf densleep
Prozess zu warten .Wenn Sie es noch genauer benötigen, müssen Sie es wahrscheinlich nur mit der Systemuhr synchronisieren und ms anstelle von vollen Sekunden in den Energiesparmodus versetzen.
Wie synchronisiere ich mit der Systemuhr? Keine Ahnung wirklich, blöder Versuch:
Standard:
Ausgabe: 003511461 010510925 016081282 021643477 028504349 03 ... (wächst weiter)
Synchronisiert:
Ausgabe: 002648691 001098397 002514348 001293023 001679137 00 ... (bleibt gleich)
quelle
sleep
Sekundenbruchteilen behandeln?sleep 0.9 || sleep 1
da ein ungültiger Parameter so ziemlich der einzige Grund dafür ist, dass der Schlaf jemals versagt.sleep 0.9
,sleep 0
von naiven Implementierungen interpretiert zu werden ( vorausgesetzt , dasatoi
würde reichen). Ich bin mir nicht sicher, ob dies tatsächlich zu einem Fehler führen würde.gdate
unter macOS verwenden, damit esdate +%N
funktioniert.)Wenn Sie Ihre Schleife in ein Skript / einen Oneliner umstrukturieren können, ist dies mit
watch
und seinerprecise
Option am einfachsten .Sie können den Effekt mit
watch -n 1 sleep 0.5
- sehen, es werden Sekunden gezählt, aber gelegentlich wird eine Sekunde übersprungen. Wenn Sie es so ausführen,watch -n 1 -p sleep 0.5
wird es zweimal pro Sekunde ausgegeben, und es werden keine Sprünge angezeigt.quelle
Das Ausführen der Vorgänge in einer Subshell, die als Hintergrundjob ausgeführt wird, würde dazu führen, dass die Vorgänge nicht so stark beeinträchtigt werden
sleep
.Die einzige Zeit, die von einer Sekunde an "gestohlen" wurde, war die Zeit, die zum Starten der Subshell benötigt wurde, sodass letztendlich eine Sekunde übersprungen wurde, aber hoffentlich seltener als der ursprüngliche Code.
Wenn der Code in der Subshell mehr als eine Sekunde benötigt, sammelt die Schleife Hintergrundjobs an und schließlich gehen die Ressourcen aus.
quelle
Eine andere Alternative (wenn Sie sie zB nicht verwenden können,
watch -p
wie von Maelstrom vorgeschlagen) istsleepenh
[ manpage ], die für diesen Zweck entwickelt wurde.Beispiel:
Beachten Sie,
sleep 0.2
dass die Simulation einige zeitaufwändige Aufgaben ausführt, die etwa 200 ms dauern. Trotzdem bleibt die Nanosekunden-Ausgabe stabil (nach Nicht-Echtzeit-OS-Standards) - dies geschieht einmal pro Sekunde:Das ist unter 1ms anders und kein Trend. Das ist ganz gut Sie sollten mit einem Sprung von mindestens 10 ms rechnen, wenn das System belastet ist - aber mit der Zeit immer noch keine Abweichung. Dh du wirst keine Sekunde verlieren.
quelle
Mit
zsh
:Wenn Ihr Schlaf nicht unterstützt Punkt Sekunden schwimmen, können Sie verwenden
zsh
‚szselect
statt (nachzmodload zsh/zselect
):Diese sollten nicht driften, solange die Befehle in der Schleife weniger als eine Sekunde dauern.
quelle
Ich hatte genau die gleiche Anforderung an ein POSIX-Shell-Skript, bei dem nicht alle Helfer (usleep, GNUsleep, sleepenh, ...) verfügbar sind.
Siehe: https://stackoverflow.com/a/54494216
quelle