問題

問題

問題

我希望能夠運行 UNIX 命令恰恰每一秒在很長一段時間內

我需要一個解決方案,該解決方案不會因為命令本身執行所需的時間而在一定時間後落後。睡覺,手錶,以及一定的蟒蛇腳本在這方面我都失敗了。

在微控制器上,例如http://Arduino.cc我會透過硬體時鐘中斷來做到這一點。我想知道是否有類似的時間精確的shell腳本解決方案。我在 StackExchange.com 中找到的所有解決方案,如果運行超過幾個小時,都會導致明顯的時間延遲。請參閱下面的詳細資訊。

實際目的/應用

nc我想透過每 1 秒透過 (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

發現於:永遠每 x 秒重複一次 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% 折扣。

答案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

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分鐘。如果您同意每分鐘累積滯後時間然後在下一分鐘重置,那麼這個基本想法可能會起作用:

* * * * * 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 分鐘,沒有一次跳過,我懷疑它會繼續這樣做,除非 a) 系統負載變得如此之高,以至於 fork() 需要超過一秒鐘或 b) 插入閏秒。

然而,它不能保證該命令以精確的秒間隔運行,因為存在一些開銷,但我懷疑它比基於中斷的解決方案要糟糕得多。

我用(納秒,GNU 擴展)運行了大約一個小時,date +%N並對其進行了一些統計。最大延遲為 1155 微秒。平均值(算術平均值)216 µs,中位數 219 µs,標準差 42 µs。 95% 的時間其運行速度都超過 270 µs。我認為除了 C 程式之外你無法擊敗它。

相關內容