Führen Sie den Unix-Befehl genau in sehr kurzen Intervallen aus, OHNE sich mit der Zeit zu verzögern

38

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 ncalle 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.
porg
quelle
5
Was ist die erforderliche Auflösung, Genauigkeit und warum benötigen Sie sie / wofür verwenden Sie sie?
jippie
Was passiert, wenn du niceden Prozess schläfst?
Tilo Wiklund
1
Haben Sie jedoch die REAL TIME-Planung verwendet, um die Verzögerung eines sleep () -Aufrufs zu minimieren?
mdpc
Mir fällt auf, dass Ihr Timing immer vom aktuellen Betriebszustand der Box abhängt. Wenn das Programm, für das Sie sich interessieren, aus dem Cache entladen wird, steigt die Zeit, es sei denn, Sie können garantieren, dass die typische Laufzeit des Programms erheblich unter dem von Ihnen gewünschten Intervall liegt. Ich möchte auf einem Echtzeitsystem sein, mit einer deutlich reduzierten Konfiguration, bei der niemand anderes angemeldet ist, oder im Einzelbenutzermodus. Wahrscheinlich ist es eine bessere Lösung, das betreffende Programm so zu ändern, dass die Schleife selbst ausgeführt wird, anstatt sie von einem anderen Programm aus aufzurufen.
Hack Saw
2
Starten Sie jeden Befehl in einem eigenen Thread, damit Ihre Zeit nicht durch E / A-bezogene Blockierungen beeinträchtigt wird.
Joel Cornett

Antworten:

12

Wie funktioniert dieses Perl-Skript, das ich gerade erstellt habe?

#!/usr/bin/perl

use strict;
use warnings;
use Time::HiRes qw/time sleep/;

sub launch {
    return if fork;
    exec @_;
    die "Couldn't exec";
}

$SIG{CHLD} = 'IGNORE';

my $interval = shift;
my $start = time();
while (1) {
    launch(@ARGV);
    $start += $interval;
    sleep $start - time();
}

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.

hhaamu
quelle
1
Ich habe es über Nacht ohne andere aktive Benutzeranwendungen mit einem Intervall von 1 Sekunde ausgeführt, und es lief 29241 Sekunden lang, ohne eine einzige übersprungene Sekunde! Das wird zu meinem Zweck passen. Dann lief ich es wieder an diesem Morgen mit einem Intervall von 0,1 Sekunden, GNU datemit +%Nund 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();
porg
Wenn Sie es mit Intervallen von 0,01 Sekunden oder 0,001 Sekunden ausführen, ist es nur eine Frage von wenigen Sekunden oder weniger, bis das Programm mit dem Fehler "negative Zeit" abgebrochen wird. Aber für meinen Zweck passt es!
Porg
28

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:

 #include<unistd.h>
 #include<signal.h>
 void tick(int sig){
     write(1, "\n", 1);
 }
 int main(){
     signal(SIGALRM, tick);
     ualarm(1000000, 1000000); //alarm in a second, and every second after that.
     for(;;)
         pause();
 }

Kompilieren

 gcc -O2 tick.c -o tick

Dann hängen Sie es wie folgt an das an, was Sie in regelmäßigen Abständen tun müssen:

./tick | while read x; do
    date "+%Y-%m-%d %H:%M:%S"
done | tee timelog-sleep.txt
Dave
quelle
Benötige ich dafür eine spezielle Shell oder C-std? Ich habe es kompiliert (was eine kleine Warnung bei fehlender Rückgabe gab), aber es wurde keine Ausgabe erzeugt.
Mathe
@math Mit -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 ./tickzeigt Ihnen, was es aus einer syscall Perspektive tut
Dave
Ich erhalte: gcc -O2 -std = c99 -o tick.c tick.c: In Funktion 'main': tick.c: 10: 5: Warnung: implizite Deklaration der Funktion 'ualarm' [-Wimplicit-function-declare ] tick.c: In Funktion 'tick': tick.c: 5: 10: Warnung: Rückgabewert von 'write' ignorieren, deklariert mit Attribut warn_unused_result [-Wunused-result] :: Scheint so, als ob mein System (Ubuntu 12.04) dies tut nicht unterstützen. Zumindest gibt es jedoch eine Manpage, die ualarm in unistd.h enthalten sollte. (gcc ist 4.6.3)
Mathe
28

Hast du es watchmit dem Parameter versucht --precise?

watch -n 1 --precise "date '+%Y-%m-%d %H:%M:%S.%N' >> ~/Desktop/timelog-watch.txt"

Von der Manpage:

Normalerweise wird dieses Intervall als die Zeitspanne zwischen dem Abschluss eines Befehlslaufs und dem Beginn des nächsten Laufs interpretiert. Mit der Option -p oder --precise können Sie jedoch versuchen, den Befehl alle Intervallsekunden auszuführen. Probieren Sie es mit ntptime aus und beobachten Sie, wie die Sekundenbruchteile (fast) gleich bleiben, im Gegensatz zum normalen Modus, in dem sie kontinuierlich ansteigen.

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:

2561 lines
start: 2012-07-17 09:46:34.938805108
end:   2012-07-17 10:29:14.938547796

Update: Die --preciseFlagge 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.patch

Daniel Kullmann
quelle
Genau der richtige Weg. Ich wünschte, ich könnte dies +10.
krlmlr
Welche Version von watchunterstützt diese Option? Es war auf keiner der Maschinen, die ich überprüft habe.
tylerl
Seine Version 0.3.0 ist die aktuelle Version unter Ubuntu 12.04. Es stammt aus Version 3.2.8-11ubuntu6 des procps-Pakets.
Daniel Kullmann
Hmm, das procps-Quellpaket unterstützt das nicht --precise. Dies ist ein Debian-Zusatz (3.2.8-9, watch_precision_time.patch)
daniel kullmann
1
Ok, aber genau wie bei mdpc in den Kommentaren zu der Frage angegeben: Dies kann auch fehlschlagen, wenn Ihr System stark ausgelastet ist. Ich habe es gerade in Verbindung mit Stress (Laden von Festplatten und Kernen) getestet und Folgendes festgestellt: 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!
Mathe
18

crontabhat 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:

* * * * * for second in $(seq 0 59); do /path/to/script.sh & sleep 1s;done

Beachten Sie, dass script.shauch 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 sleeperzeugt 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:

$ cat timelog-cron
2012-07-16 20:51:01
...
2012-07-16 22:43:00

1 Stunde 52 Minuten = 6720 Sekunden

$ wc -l timelog-cron
6720 timelog-cron

0 Zeitprobleme, 0% Rabatt. Jede Zeitansammlung wird jede Minute zurückgesetzt.

Izkata
quelle
1
Darf ich fragen, warum dies abgelehnt wurde?
Izkata
2
Es ist ein hässlicher Hack
hhaamu
2
@hhaamu Was ist daran hässlich? Allzweckbetriebssysteme auf PCs sind nicht für sehr genaue zeitkritische Vorgänge ausgelegt. Was können Sie also mehr erwarten? Wenn Sie ein "elegantes" und absolut präzises Timing wünschen, müssen Sie einen anderen CPU-Scheduler verwenden, auf einen Echtzeitkern umsteigen oder dedizierte Hardware usw. verwenden. Dies ist eine absolut legitime Lösung, für die ich keinen Grund sehe Downvotes. Es ist sicherlich eine Verbesserung gegenüber der, die nur im Hintergrund ausgeführt wurde, ohne dass die Synchronisierung regelmäßig über cron durchgeführt wurde.
jw013,
1
Plus es zu stoppen ist einfach. Sie müssen nicht riskieren, es mitten in einem Zyklus zu töten - entfernen Sie den Eintrag von der Crontab und es endet am Ende der Minute von alleine.
Izkata
Sie haben nur Glück, dass Ihr System cronauf die Sekunde genau ist, aber das ist im Allgemeinen nicht der Fall .
Dmitry Grigoryev
15

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.

tylerl
quelle
Ich halte es auch für sehr wahrscheinlich, dass die Programme porg block während der Ausführung des beabsichtigten Prozesses getestet haben - was sie logischerweise tun sollten, um zu vermeiden, dass die Maschine, auf der sie ausgeführt werden, getötet wird.
Symcbean
Unabhängig davon, ob Sie blockieren oder nicht, funktioniert der Mechanismus einwandfrei. Wenn Sie blockieren, schlafen Sie die nach dem Blockieren verbleibende Zeit. Wenn Sie nicht blockieren, schläft Ihr Timing-Thread oder -Prozess, während der andere arbeitet. So oder so, das gleiche Ergebnis.
tylerl
@tylerl: Wie würde die konkrete Kommandozeile für deine Lösung aussehen?
Porg
Ich vermute, Sie meinten dasselbe wie @lynxlynxlynx
porg
Sie müssen @porg verwenden date +%S.%N, um die Anzahl der Sekunden mit einer Genauigkeit von weniger als einer Sekunde abzurufen und usleepmit einer Genauigkeit von weniger als einer Sekunde zu schlafen, aber danach ist es nur noch eine Frage der Mathematik.
Tylerl
7

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.

Bruce Ediger
quelle
4

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.

woliveirajr
quelle
Sie können das gleiche mit regulären tun sleep, dh sleep 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.
Dmitry Grigoryev
3

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:

while [ true ]; do date "+%Y-%m-%d %H:%M:%S" & sleep 1; done | 
tee timelog-sleep.txt

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.

lynxlynxlynx
quelle
Das Problem dabei sleep 1ist, dass es garantiert mindestens eine Sekunde schläft - niemals weniger. Daher akkumuliert sich der Fehler.
Hhaamu
Der Vergleich der Timing-Ergebnisse von zwei verschiedenen Computern ist ziemlich bedeutungslos, es sei denn, Sie haben den Originalcode auf Ihrem System ausgeführt und das gleiche Ergebnis wie beim OP erhalten.
Dmitry Grigoryev
1

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.

while true; do T=$( date +%s ); while [[ $T -eq $( date +%s ) ]]; do sleep .001; done; date "+%N nanoseconds late"; done

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 durch true.

002112890 nanoseconds late
001847692 nanoseconds late
002273652 nanoseconds late
001317015 nanoseconds late
001650504 nanoseconds late
002180949 nanoseconds late
002338716 nanoseconds late
002064578 nanoseconds late
002160883 nanoseconds late

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.

jippie
quelle
1

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

cdslashetc
quelle
1

Mit ksh93(welches einen Fließkomma $SECONDSund ein eingebautes hat sleep)

typeset -F SECONDS=0
typeset -i i=0
while true; do
   cmd
   sleep "$((++i - SECONDS))"
done

Dasselbe Skript funktioniert zshauch, ruft jedoch den sleepBefehl Ihres Systems auf . zshhat eine zselecteingebaute, aber nur mit 1/100 Auflösung.

Stéphane Chazelas
quelle
0

Ich würde mit einem kleinen C-Programm gehen:

#include <sys/time.h>
#include <unistd.h>

int main(int argc, char **argv, char **envp)
{
    struct timeval start;
    int rc = gettimeofday(&start, NULL);
    if(rc != 0)
            return 1;

    for(;;)
    {
        struct timeval now;
        rc = gettimeofday(&now, NULL);
        useconds_t delay;
        if(now.tv_usec < start.tv_usec)
            delay = start.tv_usec - now.tv_usec;
        else
            delay = 1000000 - now.tv_usec + start.tv_usec;
        usleep(delay);
        pid_t pid = fork();
        if(pid == -1)
            return 1;
        if(pid == 0)
            _exit(execve(argv[1], &argv[1], envp));
    }
}

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.

Simon Richter
quelle
0

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.

fwgx
quelle
0

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.

#! /bin/sh

# chkconfig: 2345 91 61
# description: This program is used to run all programs in a directory in parallel every X times per minute. \
#              Think of this program as cron with microseconds resolution.

# Microsecond Cron
# Usage: cron-ms start
# Copyright 2014 by Marc Perkel
# docs at http://wiki.junkemailfilter.com/index.php/How_to_run_a_Linux_script_every_few_seconds_under_cron"
# Free to use with attribution

# The scheduling is done by creating directories with the number of"
# executions per minute as part of the directory name."

# Examples:
#   /etc/cron-ms/7      # Executes everything in that directory  7 times a minute
#   /etc/cron-ms/30     # Executes everything in that directory 30 times a minute
#   /etc/cron-ms/600    # Executes everything in that directory 10 times a second
#   /etc/cron-ms/2400   # Executes everything in that directory 40 times a second

basedir=/etc/cron-ms

case "$1" in

   start|restart|reload)
   $0 stop
   mkdir -p /var/run/cron-ms
   for dir in $basedir/* ; do
      $0 ${dir##*/} &
   done
   exit
   ;;

   stop)
   rm -Rf /var/run/cron-ms
   exit
   ;;

esac

# Loops per minute is passed on the command line

loops=$1
interval=$((60000000/$loops))

# Just a heartbeat signal that can be used with monit to verify it's alive

touch /var/run/cron-ms

# After a restart the PIDs will be different allowing old processes to terminate

touch /var/run/cron-ms/$$

# Sleeps until a specific part of a minute with microsecond resolution. 60000000 is full minute

usleep $(( $interval - 10#$(date +%S%N) / 1000 % $interval ))

# Deleting the PID files exit the program

if [ ! -f /var/run/cron-ms/$$ ]
then
   exit
fi

# Run all the programs in the directory in parallel

for program in $basedir/$loops/* ; do
   if [ -x $program ] 
   then
      $program &> /dev/null &
   fi
done

exec $0 $loops
user56318
quelle