
Pregunta
Me gustaría poder ejecutar un comando UNIXprecisamentecada segundodurante un largo período de tiempo.
Necesito una solución que no se retrase después de un cierto tiempo, debido al tiempo que necesita el comando para ejecutarse.dormir,mirar, y un ciertosecuencia de comandos de PythonTodo me falló en este sentido.
En el microcontrolador como elhttp://Arduino.ccLo haría a través de interrupciones del reloj de hardware. Me gustaría saber si existe una solución similar de script de shell con tiempo preciso. Todas las soluciones que encontré en StackExchange.com dieron como resultado un retraso de tiempo notable, si se ejecutaron durante horas. Vea los detalles abajo.
Propósito práctico/aplicación
Quiero probar si mi conexión de red está continuamente activa enviando marcas de tiempo a través de nc
(netcat) cada segundo.
Remitente:
precise-timestamp-generator | tee netcat-sender.txt | nc $receiver $port
Receptor:
nc -l -p $port > netcat-receiver.txt
Una vez completado, compare los dos registros:
diff netcat-sender.txt netcat-receiver.txt
Las diferencias serían las marcas de tiempo no transmitidas. A partir de esto sabría en qué momento mi LAN/WAN/ISP genera problemas.
Solución SUEÑO
while [ true ]; do date "+%Y-%m-%d %H:%M:%S" ; sleep 1; done | tee timelog-sleep.txt
Obtiene un cierto desplazamiento con el tiempo, ya que el comando dentro del bucle también lleva un poco de tiempo.
Precisión
cat timelog-sleep.txt
2012-07-16 00:45:16
[...]
2012-07-16 10:20:36
Segundos transcurridos: 34520
wc -l timelog-sleep.txt
Líneas en el archivo: 34243
Precisión resumida:
- 34520-34243 = 277 problemas de sincronización
- 34520/34243 = 1,008 = 0,8 % de descuento
Solución REPETIR PYTHON
Encontrado en:Repita un comando de Unix cada x segundos para siempre
repeat.py 1 "date '+%Y-%m-%d %H:%M:%S'" >> timelog-repeat-py.txt
Se supone que debe evitar el desplazamiento de tiempo, pero no lo hace.
Precisión
wc -l timelog-repeat-py.txt
2012-07-16 13:42:44
[...]
2012-07-16 16:45:24
Segundos transcurridos: 10960
wc -l timelog-repeat-py.txt
Líneas en el archivo: 10859
Precisión resumida:
- 10960-10859 = 101 problemas de sincronización
- 10960/10859 = 1,009 = 0,9 % de descuento
Solución VER
watch -n 1 "date '+%Y-%m-%d %H:%M:%S' >> ~/Desktop/timelog-watch.txt"
Precisión
wc -l timelog-watch.txt
2012-07-16 11:04:08
[...]
2012-07-16 13:25:47
Segundos transcurridos: 8499
wc -l timelog-watch.txt
Líneas en el archivo: 8366
Precisión resumida:
- 8499-8366 = 133 problemas de sincronización.
- 8499/8366 = 1.016 = 1.6% de descuento.
Respuesta1
¿Has probado watch
con el parámetro --precise
?
watch -n 1 --precise "date '+%Y-%m-%d %H:%M:%S.%N' >> ~/Desktop/timelog-watch.txt"
Desde la página de manual:
Normalmente, este intervalo se interpreta como la cantidad de tiempo entre la finalización de una ejecución de comando y el comienzo de la siguiente ejecución. Sin embargo, con la opción -p o --precise, puede hacer que el reloj intente ejecutar el comando cada intervalo de segundos. Pruébelo con ntptime y observe cómo las fracciones de segundo permanecen (casi) iguales, a diferencia del modo normal donde aumentan continuamente.
Sin embargo, es posible que el parámetro no esté disponible en su sistema.
También debes considerar qué debería suceder cuando la ejecución de tu programa necesite más de un segundo. ¿Debería omitirse la siguiente ejecución programada o debería ejecutarse tarde?
Actualizar: Ejecuté el script durante algún tiempo y no perdió ni un solo paso:
2561 lines
start: 2012-07-17 09:46:34.938805108
end: 2012-07-17 10:29:14.938547796
Actualizar:La --precise
bandera es una adición de Debian, sin embargo el parche es bastante simple:http://patch-tracker.debian.org/patch/series/view/procps/1:3.2.8-9squeeze1/watch_precision_time.patch
Respuesta2
El POSIXualarm()
La función le permite programar el kernel para que indique periódicamente su proceso, con una precisión de microsegundos.
Prepare un programa simple:
#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
Luego adjúntelo a lo que necesite hacer periódicamente, así:
./tick | while read x; do
date "+%Y-%m-%d %H:%M:%S"
done | tee timelog-sleep.txt
Respuesta3
crontab
tiene una resolución de 1 minuto. Si está de acuerdo con que el tiempo de retraso se acumule por ese minuto y luego se reinicie en el minuto siguiente, esta idea básica podría funcionar:
* * * * * for second in $(seq 0 59); do /path/to/script.sh & sleep 1s;done
Tenga en cuenta que script.sh
también se ejecuta en segundo plano. Esto debería ayudar a minimizar el retraso que se acumula con cada iteración del ciclo.
Sin embargo , dependiendo de cuánto retraso sleep
se genere, existe la posibilidad de que el segundo 59 se superponga con el segundo 0 del minuto siguiente.
EDITARpara agregar algunos resultados, en el mismo formato que en la pregunta:
$ cat timelog-cron
2012-07-16 20:51:01
...
2012-07-16 22:43:00
1 hora 52 minutos = 6720 segundos
$ wc -l timelog-cron
6720 timelog-cron
0 problemas de sincronización, 0% de descuento. Cualquier acumulación de tiempo se reinicia cada minuto.
Respuesta4
¿Cómo funciona este script Perl que acabo de preparar?
#!/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'
Ha estado funcionando durante 45 minutos sin un solo salto, y sospecho que continuará haciéndolo a menos que a) la carga del sistema sea tan alta que fork() tarde más de un segundo ob) se inserte un segundo intercalar.
Sin embargo, no puede garantizar que el comando se ejecute en intervalos exactos de segundos, ya que hay cierta sobrecarga, pero dudo que sea mucho peor que una solución basada en interrupciones.
Lo ejecuté durante aproximadamente una hora con date +%N
(nanosegundos, extensión GNU) y ejecuté algunas estadísticas. El retraso máximo que tuvo fue de 1.155 microsegundos. Promedio (media aritmética) 216 µs, mediana 219 µs, desviación estándar 42 µs. Funcionó a más de 270 µs el 95% del tiempo. No creo que puedas superarlo excepto con un programa en C.