Pregunta
Me gustaría poder ejecutar un comando UNIX precisamente cada segundo durante un largo período de tiempo .
Necesito una solución, que no se quede atrás después de un cierto tiempo, debido al tiempo que el comando en sí necesita para su ejecución. dormir , mirar y un cierto script de Python me fallaron a este respecto.
En el microcontrolador como el http://Arduino.cc lo haría a través de interrupciones de reloj de hardware. Me gustaría saber si existe una solución similar de script de shell con precisión de tiempo. Todas las soluciones que encontré dentro de StackExchange.com, resultaron en un notable retraso de tiempo, si se ejecuta durante horas. Vea los detalles abajo.
Propósito práctico / aplicación
Quiero probar si mi conexión de red está continuamente nc
activa enviando marcas de tiempo a través de (netcat) cada 1 segundo.
Remitente:
precise-timestamp-generator | tee netcat-sender.txt | nc $receiver $port
Receptor:
nc -l -p $port > netcat-receiver.txt
Después de la finalización, compare los dos registros:
diff netcat-sender.txt netcat-receiver.txt
Las diferencias serían las marcas de tiempo no transmitidas. De esto sabría a qué hora mi LAN / WAN / ISP causa 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 tiempo
- 34520/34243 = 1.008 = 0.8% de descuento
Solución REPETIR PYTHON
Encontrado en: Repita un comando Unix cada x segundos para siempre
repeat.py 1 "date '+%Y-%m-%d %H:%M:%S'" >> timelog-repeat-py.txt
Se supone que evita 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 tiempo
- 10960/10859 = 1.009 = 0.9% de descuento
RELOJ de solución
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 tiempo.
- 8499/8366 = 1.016 = 1.6% de descuento.
nice
el proceso que duerme?Respuestas:
¿Cómo funciona este script de Perl que acabo de crear?
Utilizar:
perl timer.pl 1 date '+%Y-%m-%d %H:%M:%S'
Ha estado funcionando 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 segundos segundos exactos, ya que hay algo de 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 al respecto. El mayor retraso fue de 1 155 microsegundos. Promedio (media aritmética) 216 µs, mediana 219 µs, desviación estándar 42 µs. Funcionó más rápido que 270 µs el 95% del tiempo. No creo que puedas vencerlo excepto con un programa en C.fuente
GNU date
con+%N
y después de sólo 3 min arrojó que el error:Time::HiRes::sleep(-0.00615549): negative time not invented yet at ~/bin/repeat.pl line 23.
Línea 23 en mi script guardado:sleep $start - time();
La
ualarm()
función POSIX le permite programar el kernel para señalar periódicamente su proceso, con una precisión de microsegundos.Prepare un programa simple:
Compilar
Luego adjúntalo a lo que necesites hacer periódicamente de esta manera:
fuente
-std=c99
, no recibirá la advertencia sobre el retorno perdido. De lo contrario, no debería necesitar nada especial. ¿Escribiste mal un cero extra?strace ./tick
le mostrará lo que está haciendo desde una perspectiva syscall¿Has probado
watch
con el parámetro--precise
?Desde la página del manual:
Sin embargo, es posible que el parámetro no esté disponible en su sistema.
También debe considerar lo que debe suceder cuando la ejecución de su programa necesita más de un segundo. ¿Debería saltarse la próxima ejecución programada, o debería ejecutarse tarde?
Actualización : Ejecuté el script por algún tiempo, y no perdió un solo paso:
Actualización: el
--precise
indicador 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.patchfuente
watch
admite esa opción? No estaba en ninguna de las máquinas que revisé.--precise
. Esta es una adición de Debian (3.2.8-9, watch_precision_time.patch)2012-07-24 07:20:21.864818595 2012-07-24 07:20:22.467458430 2012-07-24 07:20:23.068575669 2012-07-24 07:20:23.968415439
El material en tiempo real (kernel, etc.) está disponible por alguna razón!crontab
Tiene una resolución de 1 minuto. Si está de acuerdo con el tiempo de retraso acumulado por ese minuto y luego reiniciar el siguiente minuto, esta idea básica podría funcionar: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 bucle.Dependiendo de cuánto retraso
sleep
genere, existe la posibilidad de que el segundo 59 se superponga con el segundo 0 del siguiente minuto.EDITAR para agregar algunos resultados, en el mismo formato que en la pregunta:
1 hora 52 minutos = 6720 segundos
0 problemas de tiempo, 0% de descuento. En cualquier momento la acumulación se reinicia cada minuto.
fuente
cron
sea preciso para el segundo, pero no es el caso en general.Su problema es que está durmiendo durante un período de tiempo fijo después de ejecutar su programa sin tener en cuenta la cantidad de tiempo transcurrido desde la última vez que durmió.
Puede hacer esto es bash o cualquier otro lenguaje de programación, pero la clave es usar el reloj para determinar cuánto tiempo programar el próximo sueño. Antes de dormir, revise el reloj, vea cuánto tiempo le queda y duerma la diferencia.
Debido a los compromisos de programación del proceso, no está garantizado que se despierte justo en el tic del reloj, pero debe estar bastante cerca (dentro de unos pocos ms sin carga, o dentro de unos pocos cientos de ms bajo carga). Y no acumulará errores con el tiempo porque cada vez que vuelve a sincronizar en cada ciclo de suspensión y elimina cualquier error acumulado.
Si necesita presionar el reloj exactamente, entonces lo que está buscando es un sistema operativo en tiempo real , diseñado exactamente para este propósito.
fuente
date +%S.%N
para obtener la cantidad de segundos con una precisión de menos de un segundo yusleep
para dormir con una precisión de menos de un segundo, pero después de eso es solo cuestión de matemáticas.Siempre he renunciado a que algo se ejecute exactamente en intervalos. Creo que tendrá que escribir un programa en C y prestar mucha atención a no exceder la porción del intervalo de 1 segundo con su propio código. Es probable que tenga que usar procesos de subprocesamiento o de comunicación múltiple para que esto funcione. Tenga cuidado de evitar el tiempo de inicio de subprocesos o de inicio de proceso.
Una referencia que parece relevante data de 1993: un reloj de muestreo aleatorio para la estimación de la utilización de la CPU y el perfil del código . Deseará consultar el apéndice "Código fuente del adversario" para ver cómo midieron con precisión los intervalos de tiempo y "despertaron". su programa en el momento correcto. Dado que el código tiene 19 años, probablemente no se portará directa o fácilmente, pero si lo lee y trata de entenderlo, los principios involucrados podrían guiar su código.
EDITAR: Encontré otra referencia que podría ayudar: los efectos de la resolución del reloj en la programación de procesos interactivos y en tiempo real suaves que deberían ayudarlo con cualquier fondo teórico.
fuente
Eche un vistazo a nanosleep () (de http://linux.about.com/library/cmd/blcmdl2_nanosleep.htm ). En lugar de hacer que su programa duerma 1 segundo, hágalo en reposo (1 - cantidad que se tarda en ejecutar) segundos. Obtendrá una resolución mucho mejor.
fuente
sleep
, es decirsleep 0.99
. El problema es que la cantidad de tiempo que tarda en ejecutarse está lejos de ser constante, incluso su valor medio puede fluctuar con el tiempo.Intente ejecutar su comando en segundo plano para que no afecte demasiado la sincronización del bucle, pero incluso eso no será suficiente si no desea ninguna acumulación durante largos períodos de tiempo, ya que seguramente hay un costo de unos pocos milisegundos asociado.
Entonces, esto es probablemente mejor, pero también es probable que no sea lo suficientemente bueno:
En mi computadora, esto dio 2 errores en 20 minutos o 0,1 por minuto, lo que es aproximadamente una mejora de cinco veces más baja que su ejecución.
fuente
sleep 1
es que se garantiza que duerme al menos un segundo, nunca menos. Por lo tanto, el error se acumula.Feo pero funciona. Probablemente debería repensar el diseño de su programa si necesita un ciclo como este. Básicamente verifica si el segundo entero actual es igual al anterior marcado e imprime el número de nanosegundos desde el cambio del segundo. La precisión está influenciada por el sueño .001.
La precisión está en los milisegundos, siempre que la "carga útil"
date "+%N nanoseconds late"
no tarde más de un segundo. Puede reducir la carga de la CPU aumentando el período de suspensión o, si realmente no le importa, simplemente reemplace el comando de suspensióntrue
.Esta es una mala práctica porque básicamente haces una encuesta de CPU para un evento y estás desperdiciando ciclos de CPU. Es probable que desee conectarse a una interrupción del temporizador (no es posible desde bash) o usar hardware dedicado como un microcontrolador. Una PC y su sistema operativo no están diseñados para una alta precisión de sincronización.
fuente
Otro método sería utilizar una suspensión en un bucle y enviar SIGCONT desde un programa externo preciso. Enviar una señal es muy liviano y tendrá mucha menos latencia que ejecutar algo. También puede pre-poner en cola un montón de comandos con el comando "at", ya casi nadie usa "at". No estoy seguro de cuán preciso es.
Si la precisión es crítica y quiere tomar en serio esto, esto suena como el tipo de aplicación en la que normalmente usaría RTOS, que podría hacerse bajo Linux con el kernel parcheado RT-Preempt, que le dará la precisión y alguna medida de interrumpir el control, pero puede ser más molesto de lo que vale.
https://rt.wiki.kernel.org/index.php/RT_PREEMPT_HOWTO
Xenomai también podría ser útil, es una implementación RTOS completa y está portada para x86 y x86_64, pero hay algo de programación involucrada.
http://www.xenomai.org/index.php/Main_Page
fuente
Con
ksh93
(que tiene un punto flotante$SECONDS
y un incorporadosleep
)El mismo script también funcionará
zsh
pero invocará elsleep
comando de su sistema .zsh
tiene una funciónzselect
integrada, pero solo con una resolución de 1/100fuente
Me gustaría ir con un pequeño programa en C:
Este programa espera que el programa llame con la ruta completa como primer argumento, y pasa cualquier argumento restante. No esperará a que termine el comando, por lo que felizmente iniciará varias instancias.
Además, el estilo de codificación aquí es realmente descuidado, y se hacen una serie de suposiciones que pueden o no estar garantizadas por los estándares aplicables, es decir, la calidad de este código "funciona para mí".
Este programa obtendrá intervalos algo más largos o más cortos cuando el reloj se ajuste mediante NTP o configurándolo manualmente. Si el programa debe manejar esto, POSIX proporciona lo
timer_create(CLOCK_MONOTONIC, ...)
que no se ve afectado por esto.fuente
Debe estar al tanto de la hora actual y compararla con la hora de inicio. Entonces duermes una cantidad de tiempo calculada cada iteración, no una cantidad fija. De esta manera, no acumulará errores de temporización y se alejará de donde debería estar porque restablece sus temporizaciones en cada ciclo al tiempo absoluto desde el principio.
Además, algunas funciones de suspensión regresan temprano si hay una interrupción, por lo que en este caso deberá volver a llamar a su método de suspensión hasta que haya transcurrido el tiempo completo.
fuente
Aquí hay uno que es un script bash y altamente preciso. Utiliza usleep para una precisión de microsegundos.
http://wiki.junkemailfilter.com/index.php/How_to_run_a_Linux_script_every_few_seconds_under_cron
Hay 3 guiones allí. Mira el de abajo. Realizará hasta aproximadamente 2400 ejecuciones por minuto con una precisión razonable. Y es realmente simple.
fuente
Este puede ejecutarse al menos 100 veces por segundo con una resolución muy precisa.
La existencia del directorio del número de bucles por minuto crea la programación. Esta versión admite una resolución de microsegundos, suponiendo que su computadora pueda manejarlo. El número de ejecuciones por minuto no tiene que ser divisible por 60 ni está limitado a 60. Lo he probado a 6000 y funciona.
Esta versión puede instalarse en el directorio /etc/init.d y ejecutarse como un servicio.
fuente