Pregunta

Pregunta

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 watchcon 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 --precisebandera 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

crontabtiene 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.shtambié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 sleepse 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.

información relacionada