Uruchamiaj komendę unix dokładnie w bardzo krótkich odstępach czasu BEZ kumulacji opóźnienia w czasie

38

Pytanie

Chciałbym móc uruchomić polecenie UNIX dokładnie co sekundę przez długi czas .

Potrzebuję rozwiązania, które nie pozostaje w tyle po pewnym czasie, ponieważ czas potrzebny na wykonanie samego polecenia. spanie , oglądanie i pewien skrypt Pythona zawiodły mnie pod tym względem.

Na mikrokontrolerze, takim jak http://Arduino.cc , zrobiłbym to przez przerwania zegara sprzętowego. Chciałbym wiedzieć, czy istnieje podobne precyzyjne rozwiązanie skryptów powłoki. Wszystkie rozwiązania, które znalazłem w StackExchange.com, spowodowały zauważalne opóźnienie, jeśli działały przez wiele godzin. Szczegóły poniżej.

Praktyczny cel / zastosowanie

Chcę sprawdzić, czy moje połączenie sieciowe jest stale ncaktywne, wysyłając znaczniki czasu za pośrednictwem (netcat) co 1 sekundę.

Nadawca:

precise-timestamp-generator | tee netcat-sender.txt | nc $receiver $port

Odbiorca:

nc -l -p $port > netcat-receiver.txt

Po zakończeniu porównaj dwa dzienniki:

diff netcat-sender.txt netcat-receiver.txt

Różnice byłyby nieprzesłanymi znacznikami czasu. Z tego wiedziałbym, o której godzinie mój LAN / WAN / ISP sprawia problemy.


Rozwiązanie SLEEP

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

Pobiera pewne przesunięcie w czasie, ponieważ polecenie w pętli również zajmuje trochę czasu.

Precyzja

cat timelog-sleep.txt

2012-07-16 00:45:16
[...]
2012-07-16 10:20:36

Upłynęły sekundy: 34520

wc -l timelog-sleep.txt

Linie w pliku: 34243

Precyzja podsumowana:

  • 34520-34243 = 277 problemów z synchronizacją
  • 34520/34243 = 1,008 = 0,8% zniżki

Rozwiązanie POWTÓRZ PYTHON

Znalezione w: Powtarzaj polecenie Unix co x sekund na zawsze

repeat.py 1 "date '+%Y-%m-%d %H:%M:%S'" >> timelog-repeat-py.txt

Zakłada się, aby uniknąć przesunięcia czasowego, ale tego nie robi.

Precyzja

wc -l timelog-repeat-py.txt

2012-07-16 13:42:44
[...]
2012-07-16 16:45:24

Upłynęły sekundy: 10960

wc -l timelog-repeat-py.txt

Linie w pliku: 10859

Precyzja podsumowana:

  • 10960-10859 = 101 problemów z synchronizacją
  • 10960/10859 = 1,009 = 0,9% zniżki

ROZWIĄZANIE ROZWIĄZANIA

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

Precyzja

wc -l timelog-watch.txt
2012-07-16 11:04:08
[...]
2012-07-16 13:25:47

Upłynęły sekundy: 8499

wc -l timelog-watch.txt

Linie w pliku: 8366

Precyzja podsumowana:

  • 8499-8366 = 133 problemy z synchronizacją.
  • 8499/8366 = 1.016 = 1,6% zniżki.
porg
źródło
5
Jaka jest wymagana rozdzielczość, dokładność i dlaczego jej potrzebujesz / do czego jej używasz?
jippie
Co się stanie, jeśli będziesz niceśpiący?
Tilo Wiklund,
1
Czy zastanawiałeś się nad użyciem harmonogramu RZECZYWISTEGO CZASU, aby, mam nadzieję, zminimalizować opóźnienie wywołania sleep ().
mdpc
Uderza mnie, że aktualny stan urządzenia zawsze będzie wpływał na twój czas. Jeśli coś spowoduje, że program, który chcesz usunąć z pamięci podręcznej, zwiększy się z czasem, chyba że możesz zagwarantować, że typowy czas działania programu jest znacznie krótszy niż żądany interwał. Chciałbym być w systemie czasu rzeczywistego, w znacznie zredukowanej konfiguracji, bez zalogowania nikogo innego, lub w trybie pojedynczego użytkownika. Prawdopodobnie lepszym rozwiązaniem jest zmodyfikowanie danego programu w celu wykonania samej pętli, zamiast wywoływania go z innego programu.
Hack Saw
2
Uruchom każdą komendę w swoim wątku, w ten sposób blokowanie związane z IO nie skraca czasu.
Joel Cornett,

Odpowiedzi:

12

Jak działa ten skrypt Perla, który właśnie ulepszyłem?

#!/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();
}

Posługiwać się: perl timer.pl 1 date '+%Y-%m-%d %H:%M:%S'

Pracuje 45 minut bez jednego przeskoku i podejrzewam, że będzie to kontynuował, chyba że a) obciążenie systemu stanie się tak wysokie, że fork () zajmie więcej niż sekundę lub b) wstawiona zostanie sekunda przestępna.

Nie może jednak zagwarantować, że polecenie będzie uruchamiane dokładnie w drugich odstępach, ponieważ istnieje pewne obciążenie, ale wątpię, że jest znacznie gorsze niż rozwiązanie oparte na przerwie.

Uruchomiłem go przez około godzinę z date +%N(nanosekundami, rozszerzeniem GNU) i przeprowadziłem statystyki na ten temat. Największe opóźnienie miało 1 155 mikrosekund. Średnia (średnia arytmetyczna) 216 µs, mediana 219 µs, odchylenie standardowe 42 µs. Działał szybciej niż 270 µs w 95% przypadków. Nie sądzę, że można go pokonać inaczej niż programem C.

Hhaamu
źródło
1
Uruchomiłem go przez noc bez żadnych innych aktywnych aplikacji użytkownika w odstępie 1 sekundy i działał przez 29241 sekund, bez żadnej pominiętej sekundy! To będzie pasować do mojego celu. Potem prowadził ją ponownie rano w odstępie 0,1 s, GNU datez +%N, a po zaledwie 3 minutach wyrzucił ten błąd: Time::HiRes::sleep(-0.00615549): negative time not invented yet at ~/bin/repeat.pl line 23.Linia 23 w moim zapisanego skryptu:sleep $start - time();
Porg
Jeśli uruchomisz go w odstępach 0,01 sek. Lub 0,001 sek., To tylko kilka sekund lub mniej, aż program przerwie działanie z błędem „czas ujemny”. Ale do moich celów pasuje!
porg
28

Funkcja POSIX ualarm()pozwala zaplanować jądro, aby okresowo sygnalizować proces z mikrosekundową precyzją.

Przygotuj prosty program:

 #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();
 }

Skompilować

 gcc -O2 tick.c -o tick

Następnie dołącz go do wszystkiego, co musisz robić okresowo:

./tick | while read x; do
    date "+%Y-%m-%d %H:%M:%S"
done | tee timelog-sleep.txt
Dave
źródło
Czy potrzebuję do tego specjalnej powłoki lub C-std? Skompilowałem go (co dało małe ostrzeżenie o brakującym zwrocie), ale nie wygenerowano żadnych danych wyjściowych.
matematyka
@ matematyka Dzięki -std=c99nie otrzymasz ostrzeżenia o brakującym zwrocie. W przeciwnym razie nie potrzebujesz niczego specjalnego. Czy źle wpisałeś dodatkowe zero? strace ./tickpokaże ci, co robi z perspektywy systemowej
Dave
Dostaję: gcc -O2 -std = c99 -o tick tick.c tick.c: W funkcji 'main': tick.c: 10: 5: ostrzeżenie: niejawna deklaracja funkcji 'ualarm' [-Wimplicit-function-deklaration ] tick.c: W funkcji „tick”: tick.c: 5: 10: ostrzeżenie: ignorowanie zwracanej wartości „write”, zadeklarowane z atrybutem warn_unused_result [-Wunused-result] :: Wydaje się, że mój system (Ubuntu 12.04) robi nie wspieram tego. Jednak przynajmniej istnieje strona podręcznika, na której ualarm powinien znajdować się w unistd.h. (gcc to 4.6.3)
matematyka
28

Próbowałeś już watchz parametrem --precise?

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

Ze strony podręcznika:

Zwykle ten interwał jest interpretowany jako upływ czasu między zakończeniem jednego uruchomienia polecenia a początkiem następnego uruchomienia. Jednak za pomocą opcji -p lub --precise możesz podjąć próbę uruchomienia polecenia co sekundę. Wypróbuj go z ntptime i zauważ, jak ułamki sekund pozostają (prawie) takie same, w przeciwieństwie do normalnego trybu, w którym stale rosną.

Ten parametr może jednak nie być dostępny w twoim systemie.

Powinieneś również rozważyć, co powinno się stać, gdy wykonanie programu wymaga więcej niż jednej sekundy. Czy należy pominąć kolejne zaplanowane wykonanie, czy też powinno się je spóźnić?

Aktualizacja : Uruchomiłem skrypt przez jakiś czas i nie stracił ani jednego kroku:

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

Aktualizacja:--precise flaga jest dodanie Debian, plaster jest jednak dość prosta: http://patch-tracker.debian.org/patch/series/view/procps/1:3.2.8-9squeeze1/watch_precision_time.patch

Daniel Kullmann
źródło
Dokładnie tak jest. Chciałbym móc to +10.
krlmlr
Która wersja watchobsługuje tę opcję? Nie było go na żadnej z maszyn, które sprawdziłem.
tylerl
Jego wersja 0.3.0, która jest aktualną wersją na Ubuntu 12.04. Pochodzi z wersji 3.2.8-11ubuntu6 pakietu procps.
Daniel Kullmann
Hmm, pakiet źródłowy procps nie obsługuje --precise. To jest dodatek do Debiana (3.2.8-9, watch_precision_time.patch)
daniel kullmann
1
Ok, ale to samo co mdpc w komentarzach do pytania: Może się to również nie powieść, gdy twój system jest obciążony. Właśnie przetestowałem to w połączeniu ze stresem (obciążanie dysku i rdzeni) i otrzymałem to: 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 Rzeczy w czasie rzeczywistym (jądro itp.) Jest tam z jakiegoś powodu!
matematyka
18

crontabma rozdzielczość 1 minuty. Jeśli nie masz nic przeciwko gromadzeniu się opóźnienia w tej minucie, a następnie resetowaniu w następnej minucie, ten podstawowy pomysł może zadziałać:

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

Zauważ, że script.shdziała również w tle. Powinno to pomóc zminimalizować opóźnienie, które gromadzi się przy każdej iteracji pętli.

W zależności od tego, ile sleepgeneruje opóźnienie , istnieje prawdopodobieństwo, że drugie 59 pokryje się z drugim 0 następnej minuty.

EDYCJA, aby podrzucić niektóre wyniki, w tym samym formacie, co w pytaniu:

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

1 godzina 52 minuty = 6720 sekund

$ wc -l timelog-cron
6720 timelog-cron

0 problemów z synchronizacją, 0% zniżki. Akumulacja czasu resetuje się co minutę.

Izkata
źródło
1
Czy mogę zapytać, dlaczego zostało to odrzucone?
Izkata,
2
To brzydki hack
hhaamu,
2
@hhaamu Co jest w tym brzydkiego? Systemy operacyjne ogólnego przeznaczenia na komputerach PC nie są zaprojektowane do bardzo precyzyjnych operacji o krytycznym czasie, więc czego więcej można się spodziewać? Jeśli chcesz „eleganckiego” i absolutnie precyzyjnego pomiaru czasu, musisz użyć innego harmonogramu procesora lub przełączyć się na jądro w czasie rzeczywistym, lub użyć dedykowanego sprzętu itp. Jest to całkowicie uzasadnione rozwiązanie i nie widzę żadnego powodu opinie negatywne. Jest to z pewnością ulepszenie w stosunku do tego, który miał „bieg w tle” bez okresowej ponownej synchronizacji przez cron.
jw013,
1
Ponadto zatrzymanie jest łatwe. Nie musisz ryzykować zabicia go w środku cyklu - usuń wejście z crontab i kończy się samo z końcem minuty.
Izkata,
Jesteś po prostu szczęście, że w systemie cronjest dokładny co do sekundy, ale to nie w tym przypadku w ogóle.
Dmitry Grigoryev
15

Problem polega na tym, że śpisz przez określony czas po uruchomieniu programu, nie biorąc pod uwagę ilości czasu, który upłynął od ostatniego snu.

Możesz to zrobić w trybie bash lub innym języku programowania, ale kluczem jest użycie zegara, aby określić, jak długo zaplanować następny sen. Przed snem sprawdź zegar, sprawdź, ile czasu ci pozostało i spij różnicę.

Z powodu kompromisów w planowaniu procesów nie ma gwarancji, że obudzisz się natychmiast po taktowaniu zegara, ale powinieneś być dość blisko (w ciągu kilku ms rozładowane lub kilkaset ms pod obciążeniem). I nie gromadzisz błędów w czasie, ponieważ za każdym razem ponowna synchronizacja w każdym cyklu snu i usuwanie wszelkich nagromadzonych błędów.

Jeśli chcesz dokładnie zaznaczyć zegar, to szukasz systemu operacyjnego w czasie rzeczywistym , który został zaprojektowany właśnie do tego celu.

tylerl
źródło
Myślę, że jest również bardzo prawdopodobne, że programy porg przetestowały blok podczas uruchamiania zamierzonego procesu - co logicznie powinny zrobić, aby uniknąć zabicia maszyny, na której pracują.
symcbean
Bez względu na to, czy blokujesz, mechanizm działa dobrze. Jeśli zablokujesz, śpisz pozostały czas po zablokowaniu. Jeśli nie blokujesz, wątek lub proces synchronizacji śpi, podczas gdy drugi działa. Tak czy inaczej, ten sam wynik.
tylerl
@tylerl: Jak wyglądałaby konkretna linia poleceń dla twojego rozwiązania?
porg
Myślę, że miałeś na myśli to samo, co @lynxlynxlynx
porg
@porg musisz użyć, date +%S.%Naby uzyskać liczbę sekund z precyzją poniżej sekundy i usleepspać z precyzją poniżej sekundy, ale potem to tylko kwestia matematyki.
tylerl
7

Zawsze po prostu rezygnowałem z tego, że coś działa dokładnie w odstępach czasu. Myślę, że będziesz musiał napisać program w języku C i zwracać szczególną uwagę, aby nie przekroczyć części 1-sekundowego przedziału z własnym kodem. Prawdopodobnie będziesz musiał użyć wątków lub wielu wzajemnie komunikujących się procesów, aby to zadziałało. Uważaj, aby uniknąć nadmiernego czasu rozpoczynania wątku lub uruchamiania procesu.

Jedno odniesienie, które wydaje się mieć związek z 1993 r .: Randomizowany zegar próbkowania do szacowania wykorzystania procesora i profilowania kodu. Spójrz na dodatek „Kod źródłowy przeciwnika”, aby zobaczyć, jak dokładnie mierzyli odstępy czasu i „budzili się” ich program we właściwym czasie. Ponieważ kod ma 19 lat, prawdopodobnie nie można go przenieść bezpośrednio lub łatwo, ale jeśli go przeczytasz i spróbujesz go zrozumieć, zasady mogą poprowadzić twój kod.

EDYCJA: Znaleziono kolejne odniesienie, które może pomóc: Wpływ rozdzielczości zegara na planowanie interaktywnych i miękkich procesów w czasie rzeczywistym, który powinien pomóc ci na dowolnym tle teoretycznym.

Bruce Ediger
źródło
4

Spójrz na nanosleep () (z http://linux.about.com/library/cmd/blcmdl2_nanosleep.htm ). Zamiast uśpienia programu na 1 sekundę, należy go uśpić (1 - kwota do uruchomienia) sekund. Otrzymasz znacznie lepszą rozdzielczość.

woliveirajr
źródło
Możesz zrobić to samo z normalnym sleep, tj sleep 0.99. Problem polega na tym, że czas potrzebny do uruchomienia jest daleki od stałego, nawet jego średnia wartość może zmieniać się w czasie.
Dmitry Grigoryev
3

Spróbuj uruchomić komendę w tle, aby nie miało to tak dużego wpływu na taktowanie pętli, ale nawet to nie wystarczy, jeśli nie chcesz żadnej akumulacji przez długi czas, ponieważ z pewnością wiąże się to z kosztem kilku milisekund.

Tak więc jest to prawdopodobnie lepsze, ale także prawdopodobnie wciąż niewystarczające:

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

Na moim komputerze dawało to 2 błędy w ciągu 20 minut lub 0,1 na minutę, co jest mniej więcej pięciokrotną poprawą w trakcie biegu.

lynxlynxlynx
źródło
Problem sleep 1polega na tym, że gwarantuje spanie co najmniej jedną sekundę - nigdy mniej. Stąd błąd się kumuluje.
hhaamu,
Porównywanie wyników pomiaru czasu z dwóch różnych komputerów jest zupełnie bez znaczenia, chyba że uruchomiłeś oryginalny kod w systemie i uzyskałeś taki sam wynik jak OP.
Dmitry Grigoryev
1

Brzydkie, ale działa. Prawdopodobnie powinieneś przemyśleć projekt swojego programu, jeśli potrzebujesz takiej pętli. Zasadniczo sprawdza, czy bieżąca cała sekunda jest równa poprzedniej sprawdzonej i drukuje liczbę nanosekund od zmiany drugiej. Na dokładność ma wpływ sen 0,001.

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

Dokładność jest w milisekundach, pod warunkiem, że „ładowność” date "+%N nanoseconds late"nie zajmie więcej niż sekundę. Możesz zmniejszyć obciążenie procesora, wydłużając okres uśpienia lub jeśli naprawdę nie masz nic przeciwko, po prostu zastąp polecenie uśpienia przez 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

Jest to zła praktyka, ponieważ po prostu sondujesz procesor w poszukiwaniu zdarzenia i marnujesz cykle procesora. Prawdopodobnie chcesz dołączyć do przerwania timera (niemożliwe z bash) lub użyć dedykowanego sprzętu, takiego jak mikrokontroler. Komputer PC i jego system operacyjny nie są zaprojektowane z myślą o wysokiej dokładności taktowania.

jippie
źródło
1

Inną metodą byłoby użycie zawieszenia w pętli i wysłanie SIGCONT z precyzyjnego programu zewnętrznego. Wysłanie sygnału jest bardzo lekkie i będzie miało znacznie mniejsze opóźnienie niż wykonanie czegoś. Możesz także ustawić w kolejce kilka poleceń za pomocą polecenia „at”, prawie nikt już nie używa „at”. Nie jestem pewien, jak dokładnie jest to możliwe.

Jeśli precyzja jest kluczowa i chcesz poważnie o tym podejść, brzmi to jak aplikacja, w której zwykle używasz RTOS, co można by zrobić pod Linuksem z łatanym jądrem RT-Preempt, co da ci precyzję i pewną miarę przerwać kontrolę, ale może to być bardziej kłopotliwe niż warte.

https://rt.wiki.kernel.org/index.php/RT_PREEMPT_HOWTO

Xenomai również może być pomocny, jest to pełna implementacja RTOS i jest portowana na x86 i x86_64, ale wiąże się to z pewnym programowaniem.

http://www.xenomai.org/index.php/Main_Page

cdslashetc
źródło
1

Z ksh93(który ma zmiennoprzecinkowy $SECONDSi wbudowany sleep)

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

Ten sam skrypt również będzie działał, zshale wywoła sleeppolecenie systemu . zshma zselectwbudowane, ale tylko w rozdzielczości 1/100.

Stéphane Chazelas
źródło
0

Wybrałbym mały program C:

#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));
    }
}

Ten program oczekuje, że program zadzwoni z pełną ścieżką jako pierwszym argumentem i przekaże pozostałe argumenty. Nie będzie czekać na zakończenie polecenia, więc z przyjemnością uruchomi wiele instancji.

Także styl kodowania jest tutaj naprawdę niedbały i poczyniono szereg założeń, które mogą, ale nie muszą być zagwarantowane przez obowiązujące standardy, tj. Jakość tego kodu jest „dla mnie”.

Ten program będzie miał nieco dłuższe lub krótsze interwały, gdy zegar jest regulowany przez NTP lub ręcznie. Jeśli program powinien to obsłużyć, POSIX zapewnia to, na timer_create(CLOCK_MONOTONIC, ...)co nie ma to wpływu.

Simon Richter
źródło
0

Powinieneś śledzić aktualny czas i porównywać go z czasem rozpoczęcia. Więc śpisz obliczoną ilość czasu każdej iteracji, a nie stałą ilość. W ten sposób nie będziesz kumulować błędów pomiaru czasu i odejdziesz od miejsca, w którym powinieneś być, ponieważ od początku resetujesz czasy każdej pętli do czasu bezwzględnego.

Również niektóre funkcje snu wracają wcześniej, jeśli nastąpi przerwa, więc w takim przypadku będziesz musiał ponownie wywołać metodę snu, aż upłynie pełny czas.

fwgx
źródło
0

Ten może działać co najmniej 100 razy na sekundę z bardzo dokładną rozdzielczością.

Istnienie katalogu z liczbą pętli na minutę tworzy harmonogram. Ta wersja obsługuje rozdzielczość mikrosekundową, zakładając, że komputer może to obsłużyć. Liczba egzekucji na minutę nie musi być równomiernie podzielna przez 60, ani nie jest ograniczona do 60. Przetestowałem to do 6000 i działa.

Tę wersję można zainstalować w katalogu /etc/init.d i uruchomić jako usługę.

#! /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
użytkownik56318
źródło