質問
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
完了後、2つのログを比較します。
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
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"
マニュアルページから:
通常、この間隔は、1つのコマンドの実行を完了してから次のコマンドを開始するまでの時間として解釈されます。ただし、-pまたは--preciseオプションを使用すると、ウォッチに間隔秒ごとにコマンドを実行させることができます。 ntptimeを試して、通常モードで継続的に増加するのではなく、少数秒が(ほぼ)同じままになる方法を確認してください。
ただし、このパラメーターはシステムで使用できない可能性があります。
また、プログラムの実行に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
POSIXualarm()
関数を使用すると、マイクロ秒単位の精度でプロセスに定期的に信号を送信するようにカーネルを予約できます。
簡単なプログラムを書いてください:
#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が次の分の秒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'
1回もスキップせずに45分間実行され、a)システムの負荷が高すぎてfork()が1秒以上かかり、b)うるう秒が挿入されない限り、継続して実行されると疑われます。
ただし、少しオーバーヘッドがあるため、コマンドが正確な秒間隔で実行されるという保証はありませんが、割り込みベースのソリューションよりはるかに悪いと思います。
(ナノ秒、GNU拡張)を使用して約1時間実行し、date +%N
それに関するいくつかの統計を実行しました。最大遅延は1155マイクロ秒です。平均(算術平均)は216μs、中央値は219μs、標準偏差は42μsです。 95%の時間中に270μsを超えて実行されます。 C番組以外は勝てないと思います。