Вопрос

Вопрос

Вопрос

Я хотел бы иметь возможность запускать команду UNIXименно таккаждую секундув течение длительного периода времени.

Мне нужно решение, которое не отстает по истечении определенного времени, поскольку самой команде требуется время на выполнение.спать,смотреть, и определенныйскрипт на Pythonвсе меня подвели в этом отношении.

На микроконтроллерах, таких какhttp://Arduino.ccЯ бы сделал это через аппаратные прерывания часов. Я хотел бы узнать, есть ли похожее решение для скрипта оболочки с точным временем. Все решения, которые я нашел на StackExchange.com, привели к заметной задержке, если они выполнялись в течение нескольких часов. Подробности см. ниже.

Практическое назначение/применение

Я хочу проверить, постоянно ли работает мое сетевое соединение, отправляя временные метки через nc(netcat) каждую секунду.

Отправитель:

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

Получатель:

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

После завершения сравните два журнала:

diff netcat-sender.txt netcat-receiver.txt

Диффы будут непереданными временными метками. Из этого я узнаю, в какое время мой LAN / WAN / ISP создает проблемы.


Решение СОН

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

Получает определенное смещение с течением времени, так как команда внутри цикла также занимает немного времени.

Точность

cat timelog-sleep.txt

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

Прошло секунд: 34520

wc -l timelog-sleep.txt

Строк в файле: 34243

Точность обобщена:

  • 34520-34243 = 277 проблем с синхронизацией
  • 34520/34243 = 1,008 = скидка 0,8 %

Решение ПОВТОРИТЬ PYTHON

Найдено по адресу:Повторять команду Unix каждые x секунд вечно

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

Предполагается, что это позволит избежать смещения времени, но этого не происходит.

Точность

wc -l timelog-repeat-py.txt

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

Прошло секунд: 10960

wc -l timelog-repeat-py.txt

Строк в файле: 10859

Точность обобщена:

  • 10960-10859 = 101 проблема с синхронизацией
  • 10960/10859 = 1,009 = скидка 0,9 %

Решение СМОТРЕТЬ

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

Точность

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

Прошло секунд: 8499

wc -l timelog-watch.txt

Строк в файле: 8366

Точность обобщена:

  • 8499-8366 = 133 проблемы с синхронизацией.
  • 8499/8366 = 1,016 = скидка 1,6 %.

решение1

Вы пробовали watchс параметром --precise?

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

Из страницы руководства:

Обычно этот интервал интерпретируется как количество времени между завершением одного запуска команды и началом следующего запуска. Однако с помощью опции -p или --precise вы можете заставить watch пытаться запустить команду каждые интервал секунд. Попробуйте сделать это с ntptime и обратите внимание, как дробные секунды остаются (почти) такими же, в отличие от обычного режима, где они непрерывно увеличиваются.

Однако этот параметр может быть недоступен в вашей системе.

Вы также должны подумать, что должно произойти, когда выполнение вашей программы требует больше одной секунды. Следует ли пропустить следующее запланированное выполнение или запустить его позже?

Обновлять: Я некоторое время запускал скрипт, и он не потерял ни одного шага:

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

Обновлять:Флаг --preciseявляется дополнением Debian, однако патч довольно прост:http://patch-tracker.debian.org/patch/series/view/procps/1:3.2.8-9squeeze1/watch_precision_time.patch

решение2

POSIX-стандартualarm()Функция позволяет вам запланировать ядру периодическую отправку сигналов вашему процессу с точностью до микросекунды.

Составьте простую программу:

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

Компилировать

 gcc -O2 tick.c -o tick

Затем прикрепите его к тому, что вам нужно делать периодически, например:

./tick | while read x; do
    date "+%Y-%m-%d %H:%M:%S"
done | tee timelog-sleep.txt

решение3

crontabимеет разрешение в 1 минуту. Если вас устраивает время задержки, накапливающееся в течение этой минуты, а затем сбрасывающееся в следующую минуту, эта базовая идея может сработать:

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

Обратите внимание, что script.shтакже выполняется в фоновом режиме. Это должно помочь минимизировать задержку, которая накапливается с каждой итерацией цикла.

Однако в зависимости от того, насколько велико отставание sleep, существует вероятность того, что секунда 59 наложится на секунду 0 следующей минуты.

РЕДАКТИРОВАТЬчтобы добавить некоторые результаты в том же формате, что и в вопросе:

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

1 час 52 минуты = 6720 секунд

$ wc -l timelog-cron
6720 timelog-cron

0 проблем с хронометражем, 0% скидки. Любое накопление времени сбрасывается каждую минуту.

решение4

Как работает этот скрипт Perl, который я только что написал?

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

Использовать:perl timer.pl 1 date '+%Y-%m-%d %H:%M:%S'

Он работает уже 45 минут без единого сбоя, и я подозреваю, что так будет продолжаться, если только а) нагрузка на систему не станет настолько высокой, что fork() будет занимать больше секунды, или б) не будет добавлена ​​дополнительная секунда.

Однако он не может гарантировать, что команда будет выполняться с точным секундным интервалом, поскольку возникают некоторые накладные расходы, но я сомневаюсь, что это намного хуже, чем решение на основе прерываний.

Я запустил его примерно на час с date +%N(наносекундами, расширением GNU) и запустил некоторую статистику. Наибольшая задержка составила 1 155 микросекунд. Среднее (среднее арифметическое) 216 мкс, медиана 219 мкс, стандартное отклонение 42 мкс. Он работал быстрее 270 мкс в 95% случаев. Я не думаю, что вы сможете превзойти его, кроме как программой на C.

Связанный контент