
Pergunta
Eu gostaria de poder executar um comando UNIXprecisamentetodo segundodurante um longo período de tempo.
Preciso de uma solução que não fique para trás depois de um certo tempo, por causa do tempo que o próprio comando precisa para ser executado.dormir,assistir, e um certoscript pythontodos falharam comigo nesse aspecto.
Nos microcontroladores como ohttp://Arduino.ccEu faria isso através de interrupções de clock de hardware. Gostaria de saber se existe uma solução semelhante de script de shell com precisão de tempo. Todas as soluções que encontrei no StackExchange.com resultaram em um atraso de tempo perceptível, se executadas por horas. Veja os detalhes abaixo.
Finalidade prática/aplicação
Quero testar se minha conexão de rede está continuamente ativa enviando carimbos de data/hora via nc
(netcat) a cada 1 segundo.
Remetente:
precise-timestamp-generator | tee netcat-sender.txt | nc $receiver $port
Receptor:
nc -l -p $port > netcat-receiver.txt
Após a conclusão, compare os dois logs:
diff netcat-sender.txt netcat-receiver.txt
As diferenças seriam os carimbos de data/hora não transmitidos. A partir disso eu saberia a que horas minha LAN/WAN/ISP apresenta problemas.
Solução SONO
while [ true ]; do date "+%Y-%m-%d %H:%M:%S" ; sleep 1; done | tee timelog-sleep.txt
Obtém um certo deslocamento ao longo do tempo, pois o comando dentro do loop também demora um pouco.
Precisão
cat timelog-sleep.txt
2012-07-16 00:45:16
[...]
2012-07-16 10:20:36
Segundos decorridos: 34520
wc -l timelog-sleep.txt
Linhas no arquivo: 34243
Precisão resumida:
- 34520-34243 = 277 problemas de tempo
- 34520/34243 = 1,008 = 0,8% de desconto
Solução REPETIR PYTHON
Encontrado em:Repita um comando Unix a cada x segundos para sempre
repeat.py 1 "date '+%Y-%m-%d %H:%M:%S'" >> timelog-repeat-py.txt
Supõe-se que evite o deslocamento de tempo, mas não o faz.
Precisão
wc -l timelog-repeat-py.txt
2012-07-16 13:42:44
[...]
2012-07-16 16:45:24
Segundos decorridos: 10960
wc -l timelog-repeat-py.txt
Linhas no arquivo: 10859
Precisão resumida:
- 10960-10859 = 101 problemas de temporização
- 10960/10859 = 1,009 = 0,9% de desconto
Solução ASSISTA
watch -n 1 "date '+%Y-%m-%d %H:%M:%S' >> ~/Desktop/timelog-watch.txt"
Precisão
wc -l timelog-watch.txt
2012-07-16 11:04:08
[...]
2012-07-16 13:25:47
Segundos decorridos: 8499
wc -l timelog-watch.txt
Linhas no arquivo: 8366
Precisão resumida:
- 8499-8366 = 133 problemas de temporização.
- 8499/8366 = 1,016 = 1,6% de desconto.
Responder1
Você já tentou watch
com o parâmetro --precise
?
watch -n 1 --precise "date '+%Y-%m-%d %H:%M:%S.%N' >> ~/Desktop/timelog-watch.txt"
Na página de manual:
Normalmente, esse intervalo é interpretado como o tempo entre a conclusão de uma execução de comando e o início da próxima execução. No entanto, com a opção -p ou --precise, você pode fazer uma tentativa de observação para executar o comando a cada intervalo de segundos. Experimente com ntptime e observe como os segundos fracionários permanecem (quase) iguais, ao contrário do modo normal, onde aumentam continuamente.
No entanto, o parâmetro pode não estar disponível em seu sistema.
Você também deve considerar o que deve acontecer quando a execução do seu programa precisar de mais de um segundo. A próxima execução agendada deve ser ignorada ou atrasada?
Atualizar: Executei o script por algum tempo e ele não perdeu uma única etapa:
2561 lines
start: 2012-07-17 09:46:34.938805108
end: 2012-07-17 10:29:14.938547796
Atualizar:A --precise
bandeira é uma adição do Debian, mas o patch é bastante simples:http://patch-tracker.debian.org/patch/series/view/procps/1:3.2.8-9squeeze1/watch_precision_time.patch
Responder2
O POSIXualarm()
A função permite agendar o kernel para sinalizar periodicamente seu processo, com precisão de microssegundos.
Prepare um programa simples:
#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();
}
Compilar
gcc -O2 tick.c -o tick
Em seguida, anexe-o a tudo o que você precisa fazer periodicamente, assim:
./tick | while read x; do
date "+%Y-%m-%d %H:%M:%S"
done | tee timelog-sleep.txt
Responder3
crontab
tem resolução de 1 minuto. Se você concordar com o tempo de atraso acumulado naquele minuto e redefinido no minuto seguinte, esta ideia básica pode funcionar:
* * * * * for second in $(seq 0 59); do /path/to/script.sh & sleep 1s;done
Observe que script.sh
também é executado em segundo plano. Isso deve ajudar a minimizar o atraso acumulado a cada iteração do loop.
Dependendo de quanto atraso sleep
é gerado, existe, no entanto, a chance do segundo 59 se sobrepor ao segundo 0 do minuto seguinte.
EDITARlançar alguns resultados, no mesmo formato da pergunta:
$ cat timelog-cron
2012-07-16 20:51:01
...
2012-07-16 22:43:00
1 hora e 52 minutos = 6720 segundos
$ wc -l timelog-cron
6720 timelog-cron
0 problemas de tempo, 0% de desconto. Qualquer acumulação de tempo é reiniciada a cada minuto.
Responder4
Como funciona esse script Perl que acabei de criar?
#!/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();
}
Usar:perl timer.pl 1 date '+%Y-%m-%d %H:%M:%S'
Ele está funcionando há 45 minutos sem um único salto, e suspeito que continuará assim, a menos que a) a carga do sistema fique tão alta que fork() demore mais de um segundo ou b) um segundo bissexto seja inserido.
Ele não pode garantir, entretanto, que o comando seja executado em intervalos exatos de segundos, pois há alguma sobrecarga, mas duvido que seja muito pior do que uma solução baseada em interrupções.
Executei-o por cerca de uma hora com date +%N
(nanossegundos, extensão GNU) e executei algumas estatísticas sobre ele. O maior atraso que teve foi de 1.155 microssegundos. Média (média aritmética) 216 µs, mediana 219 µs, desvio padrão 42 µs. Ele funcionou mais rápido que 270 µs em 95% do tempo. Eu não acho que você possa vencê-lo, exceto por um programa C.