
質問
UNIXコマンドを実行できるようにしたい正確に一秒ごと長期間にわたって。
コマンド自体の実行には時間がかかるため、一定時間経過後に遅延が発生しないソリューションが必要です。寝る、時計、そしてあるPython スクリプトこの点に関しては、すべてが失敗でした。
マイクロコントローラでは、http://Arduino.cc私はハードウェア クロック割り込みを使用してこれを実行します。同様の正確な時間を持つシェル スクリプト ソリューションがあるかどうか知りたいです。StackExchange.com 内で見つけたすべてのソリューションでは、数時間にわたって実行すると、顕著な時間差が生じます。詳細は以下を参照してください。
実用目的/用途
nc
1 秒ごとに (netcat)経由でタイムスタンプを送信して、ネットワーク接続が継続的に稼働しているかどうかをテストします。
送信者:
precise-timestamp-generator | tee netcat-sender.txt | nc $receiver $port
受信者:
nc -l -p $port > netcat-receiver.txt
完了したら、2 つのログを比較します。
diff netcat-sender.txt netcat-receiver.txt
差分は、送信されなかったタイムスタンプになります。これにより、LAN / WAN / ISP に問題が発生した時刻がわかります。
ソリューション SLEEP
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 % オフ
ソリューション REPEAT 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"
man ページから:
通常、この間隔は、コマンドの 1 回の実行が完了してから次の実行が開始されるまでの時間として解釈されます。ただし、-p または --precise オプションを使用すると、watch が interval 秒ごとにコマンドを実行しようと試みるようにすることができます。ntptime で試してみると、秒の小数部が (ほぼ) 同じままであることがわかります。通常モードでは秒の小数部が継続的に増加します。
ただし、このパラメータはシステム上で使用できない可能性があります。
プログラムの実行に 1 秒以上かかる場合に何が起こるかについても考慮する必要があります。次にスケジュールされている実行をスキップするべきでしょうか、それとも遅れて実行するべきでしょうか。
アップデート: しばらくスクリプトを実行しましたが、1 つのステップも失われませんでした。
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 分です。1 分ごとに遅延時間が蓄積され、次の 1 分でリセットされることに問題がない場合は、次の基本的なアイデアが役立ちます。
* * * * * for second in $(seq 0 59); do /path/to/script.sh & sleep 1s;done
バックグラウンドでも実行されることに注意してくださいscript.sh
。これにより、ループの各反復で蓄積される遅延を最小限に抑えることができます。
ただし、発生するラグの量によってはsleep
、59 秒が次の 1 分間の 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% です。時間の累積は 1 分ごとにリセットされます。
答え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 分間、一度もスキップすることなく実行されており、(a) システム負荷が非常に高くなって fork() に 1 秒以上かかるか、(b) うるう秒が挿入されない限り、この状態が続くと思われます。
ただし、オーバーヘッドがあるため、コマンドが正確に 1 秒間隔で実行されることを保証することはできませんが、割り込みベースのソリューションよりもはるかに悪いとは思いません。
私はこれを (ナノ秒、GNU 拡張) で約 1 時間実行しdate +%N
、統計をいくつか実行しました。最大の遅延は 1,155 マイクロ秒でした。平均 (算術平均) 216 µs、中央値 219 µs、標準偏差 42 µs。95% の時間で 270 µs より速く実行されました。C プログラム以外ではこれを上回ることはできないと思います。