Вопрос
Я хотел бы иметь возможность выполнять команду UNIX точно каждую секунду в течение длительного периода времени .
Мне нужно решение, которое не отстает от определенного времени из-за времени, необходимого самой команде для выполнения. сон , часы и некий скрипт на python все меня подвели в этом отношении.
На микроконтроллере, таком как http://Arduino.cc, я бы делал это с помощью аппаратных прерываний часов. Я хотел бы знать, есть ли подобное решение для сценариев оболочки с точным временем. Все решения, которые я нашел на StackExchange.com, привели к заметной задержке во времени, если работать в течение нескольких часов. Подробности смотрите ниже.
Практическое назначение / применение
Я хочу проверить, постоянно ли работает мое сетевое соединение, посылая временные метки через nc
(netcat) каждую 1 секунду.
Отправитель:
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%
Решение ПОВТОРНЫЙ ПИТОН
Найдено в: Повторите команду Unix каждые х секунд навсегда
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%.
nice
процесс, который спит?Ответы:
Как работает этот Perl-скрипт, который я только что написал?
Использование:
perl timer.pl 1 date '+%Y-%m-%d %H:%M:%S'
Он работал 45 минут без единого пропуска, и я подозреваю, что он будет продолжать это делать, если а) нагрузка на систему не станет настолько высокой, что fork () займет больше секунды или б) будет добавлена високосная секунда.
Однако он не может гарантировать, что команда выполняется с точными вторыми интервалами, поскольку есть некоторые издержки, но я сомневаюсь, что это намного хуже, чем решение на основе прерываний.
Я запускал его около часа с
date +%N
(наносекунды, расширение GNU) и запускал некоторую статистику по нему. Самое большое отставание было 1 155 микросекунд. Среднее (среднее арифметическое) 216 мкс, медиана 219 мкс, стандартное отклонение 42 мкс. Он работал быстрее, чем 270 мкс в 95% случаев. Я не думаю, что вы можете победить это, кроме как на C-программе.источник
GNU date
с+%N
и только после 3 минут он бросил эту ошибку:Time::HiRes::sleep(-0.00615549): negative time not invented yet at ~/bin/repeat.pl line 23.
Line 23 в моем сохраненном сценарии:sleep $start - time();
Функция POSIX
ualarm()
позволяет планировать ядро для периодической сигнализации вашего процесса с точностью до микросекунды.Подбери простую программу:
Compile
Затем прикрепите его к тому, что вам нужно, периодически, например, так:
источник
-std=c99
, вы не получите предупреждение о пропущенном возврате. В противном случае вам не нужно ничего особенного. Вы неправильно набрали лишний ноль?strace ./tick
покажет вам, что он делает с точки зрения системного вызоваВы пробовали
watch
с параметром--precise
?Со страницы руководства:
Однако этот параметр может быть недоступен в вашей системе.
Вы также должны учитывать, что должно произойти, когда выполнение вашей программы требует более одной секунды. Должно ли быть пропущено следующее запланированное выполнение или оно должно быть запущено поздно?
Обновление : я запустил скрипт некоторое время, и он не потерял ни одного шага:
Обновление:
--precise
флаг является дополнением Debian, патч, однако , довольно просто: http://patch-tracker.debian.org/patch/series/view/procps/1:3.2.8-9squeeze1/watch_precision_time.patchисточник
watch
поддерживает эту опцию? Это было ни на одной из машин, которые я проверял.--precise
. Это дополнение к Debian (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
режиме реального времени (ядро и т. Д.) Есть причина по причине!crontab
имеет разрешение 1 минута. Если вы согласны с тем, что время задержки накапливается за одну минуту, а затем сбрасывается на следующую минуту, эта базовая идея может сработать:Обратите внимание, что
script.sh
также работает в фоновом режиме. Это должно помочь минимизировать отставание, которое накапливается при каждой итерации цикла.В зависимости от того, сколько лага
sleep
генерирует, есть вероятность того, что секунда 59 будет совпадать со секундой 0 следующей минуты.РЕДАКТИРОВАТЬ, чтобы добавить некоторые результаты в том же формате, что и в вопросе:
1 час 52 минуты = 6720 секунд
0 проблем с синхронизацией, 0% скидка. В любое время накопление сбрасывается каждую минуту.
источник
cron
точностью до секунды, но это не так в общем.Ваша проблема в том, что вы спите в течение определенного периода времени после запуска вашей программы, не принимая во внимание количество времени, прошедшее с момента вашего последнего сна.
Вы можете сделать это на bash или на любом другом языке программирования, но ключ заключается в том, чтобы использовать часы, чтобы определить, как долго планировать следующий сон. Перед сном проверьте часы, посмотрите, сколько времени у вас осталось, и усните разницу.
Из-за компромиссов в планировании процессов вы не гарантированно просыпаетесь прямо на такте, но вы должны быть достаточно близко (в течение нескольких мс без нагрузки или в течение нескольких сотен мс под нагрузкой). И вы не будете накапливать ошибки с течением времени, потому что каждый раз вы будете синхронизироваться в каждом цикле сна и удаляете любую накопленную ошибку.
Если вам нужно точно нажать на часы, то вам нужна операционная система реального времени , предназначенная именно для этой цели.
источник
date +%S.%N
чтобы получить количество секунд с точностьюusleep
до секунды, и спать с точностью до секунды, но после этого это просто вопрос математики.Я всегда просто разочаровывался в том, что что-то работает точно в промежутке. Я думаю, вам придется написать программу на C и уделить особое внимание тому, чтобы не превышать часть 1-секундного интервала с вашим собственным кодом. Вам, вероятно, придется использовать многопоточность или несколько взаимодействующих процессов, чтобы заставить это работать. Будьте осторожны, чтобы избежать чрезмерных затрат времени запуска потока или запуска процесса.
Одна ссылка, которая, похоже, относится к 1993 году: часы рандомизированной выборки для оценки использования ЦП и профилирования кода. Вам может понадобиться взглянуть на приложение «Исходный код злоумышленника», чтобы увидеть, как они точно измеряли временные интервалы и «проснулись». их программа в правильное время. Так как коду 19 лет, он, вероятно, не будет портировать напрямую или легко, но если вы прочитаете его и попытаетесь понять, принципы, которыми вы руководствуетесь, могут направлять ваш код.
РЕДАКТИРОВАТЬ: нашел другую ссылку, которая может помочь: Влияние разрешения часов на планирование интерактивных и мягких процессов в реальном времени, которые должны помочь вам с любой теоретической подготовкой.
источник
Посмотрите на nanosleep () (с http://linux.about.com/library/cmd/blcmdl2_nanosleep.htm ). Вместо того, чтобы заставить вашу программу спать 1 секунду, заставьте ее спать (1 - количество, необходимое для запуска) секунд. Вы получите намного лучшее разрешение.
источник
sleep
, то естьsleep 0.99
. Проблема в том, что количество времени, которое требуется для запуска, далеко от постоянного, даже его среднее значение может колебаться со временем.Попробуйте запустить свою команду в фоновом режиме, чтобы она не сильно влияла на синхронизацию цикла, но даже этого будет недостаточно, если вы не хотите накапливать данные в течение длительного времени, поскольку с ней, безусловно, связаны затраты в несколько миллисекунд.
Таким образом, это, вероятно, лучше, но, вероятно, все еще недостаточно хорошо:
На моем компьютере это дало 2 ошибки за 20 минут или 0,1 в минуту, что примерно в пять раз меньше, чем за пробежку.
источник
sleep 1
том, что он спит не менее одной секунды, а не меньше. Следовательно ошибка накапливается.Уродливо, но это работает. Вероятно, вам следует переосмыслить дизайн вашей программы, если вам нужен такой цикл. Он в основном проверяет, равна ли текущая целая секунда предыдущей проверенной секунде, и печатает количество наносекунд с момента изменения секунды. На точность влияет сон .001.
Точность указывается в миллисекундах, при условии, что «полезная нагрузка»
date "+%N nanoseconds late"
занимает не более секунды. Вы можете снизить нагрузку на процессор, увеличив период ожидания или, если действительно не возражаете, просто замените команду sleep наtrue
.Это плохая практика, потому что вы в основном проводите опрос CPU для события и вы тратите впустую циклы CPU. Вы, вероятно, хотите подключиться к прерыванию по таймеру (это невозможно из bash) или использовать выделенное оборудование, такое как микроконтроллер. ПК и его операционная система не рассчитаны на высокую точность синхронизации.
источник
Другой метод - использовать приостановку в цикле и отправлять SIGCONT из точной внешней программы. Посылка сигнала очень легка и будет иметь намного меньшую задержку, чем выполнение чего-либо. Вы также можете поставить в очередь кучу команд с помощью команды «at», которую вряд ли кто-нибудь использует в «at», я не уверен, насколько она точна.
Если точность критична, и вы хотите серьезно отнестись к этому, это похоже на приложение, в котором вы обычно используете RTOS, что может быть сделано под Linux с исправленным ядром RT-Preempt, что даст вам точность и некоторую меру контроль прерываний, но это может быть более беспокойным, чем стоит.
https://rt.wiki.kernel.org/index.php/RT_PREEMPT_HOWTO
Xenomai также может быть полезен, это полная реализация RTOS и портирована для x86 и x86_64, но есть некоторое программирование.
http://www.xenomai.org/index.php/Main_Page
источник
С
ksh93
(который имеет плавающую точку$SECONDS
и встроенныйsleep
)Тот же сценарий будет работать,
zsh
но вызоветsleep
команду вашей системы .zsh
имеетzselect
встроенный, но только с разрешением 1/100.источник
Я бы пошел с небольшой программой на C:
Эта программа ожидает, что программа вызовет полный путь в качестве первого аргумента, и передаст все оставшиеся аргументы. Он не будет ждать завершения команды, поэтому он с радостью запустит несколько экземпляров.
Кроме того, стиль кодирования здесь действительно небрежный, и сделан ряд допущений, которые могут или не могут быть гарантированы применимыми стандартами, то есть качество этого кода «работает для меня».
Эта программа получит несколько более длинные или короткие интервалы, когда часы будут настроены с помощью NTP или вручную. Если программа должна обрабатывать это, POSIX предоставляет,
timer_create(CLOCK_MONOTONIC, ...)
что не влияет на это.источник
Вы должны отслеживать текущее время и сравнивать его с временем начала. Таким образом, вы спите рассчитанное количество времени на каждую итерацию, а не фиксированное количество. Таким образом, вы не будете накапливать ошибки синхронизации и переходить от того, где вы должны быть, потому что вы сбрасываете свои тайминги в каждом цикле на абсолютное время от начала.
Кроме того, некоторые функции сна возвращаются рано, если происходит прерывание, поэтому в этом случае вам придется снова вызывать свой метод сна, пока не пройдет полное количество времени.
источник
Вот сценарий bash, очень точный. Он использует usleep для микросекундной точности.
http://wiki.junkemailfilter.com/index.php/How_to_run_a_Linux_script_every_few_seconds_under_cron
Там есть 3 скрипа. Посмотрите на тот, что внизу. Будет выполнять до 2400 выполнений в минуту с разумной точностью. И это действительно просто.
источник
Этот может работать по крайней мере 100 раз в секунду с очень точным разрешением.
Наличие каталога по количеству циклов в минуту создает расписание. Эта версия поддерживает микросекундное разрешение, если ваш компьютер может справиться с этим. Количество выполнений в минуту не должно делиться равномерно на 60 и не ограничиваться 60. Я проверил его до 6000, и он работает.
Эту версию можно установить в каталоге /etc/init.d и запустить как службу.
источник