Estoy ejecutando este ciclo para verificar e imprimir algunas cosas cada segundo. Sin embargo, debido a que los cálculos toman unos pocos cientos de milisegundos, el tiempo impreso a veces se salta un segundo.
¿Hay alguna forma de escribir un bucle que me garantice obtener una copia impresa cada segundo? (Siempre que, por supuesto, los cálculos en el ciclo tomen menos de un segundo :))
while true; do
TIME=$(date +%H:%M:%S)
# some calculations which take a few hundred milliseconds
FOO=...
BAR=...
printf '%s %s %s\n' $TIME $FOO $BAR
sleep 1
done
bash
timestamps
sleep
outrin
fuente
fuente
sched(7)
API (POSIX: ver<sched.h>
y páginas enlazadas desde allí), básicamente no puede tener garantías en tiempo real de este formulario.Respuestas:
Para estar un poco más cerca del código original, lo que hago es:
Esto cambia un poco la semántica: si sus cosas tomaron menos de un segundo, simplemente esperará a que pase el segundo completo. Sin embargo, si sus cosas tardan más de un segundo por cualquier motivo, no seguirá generando aún más subprocesos sin un final.
Por lo tanto, sus cosas nunca se ejecutan en paralelo y no en segundo plano, por lo que las variables funcionan como se esperaba
Tenga en cuenta que si también inicia tareas en segundo plano adicionales, tendrá que cambiar las
wait
instrucciones para esperar solo elsleep
proceso específicamente.Si necesita que sea aún más preciso, probablemente solo tenga que sincronizarlo con el reloj del sistema y suspender ms en lugar de segundos completos.
¿Cómo sincronizar con el reloj del sistema? No tengo idea realmente, intento estúpido:
Defecto:
Salida: 003511461 010510925 016081282 021643477 028504349 03 ... (sigue creciendo)
Sincronizado:
Salida: 002648691 001098397 002514348 001293023 001679137 00 ... (permanece igual)
fuente
sleep
manejar segundos fraccionarios?sleep 0.9 || sleep 1
como un parámetro no válido, es prácticamente la única razón para que el sueño falle.sleep 0.9
interpreten comosleep 0
implementaciones ingenuas (dado que eso es loatoi
que haría). No estoy seguro si eso realmente resultaría en un error.gdate
en MacOS para hacerdate +%N
el trabajo.)Si puede reestructurar su ciclo en un script / oneliner, entonces la forma más sencilla de hacerlo es con
watch
y suprecise
opción.Puede ver el efecto con
watch -n 1 sleep 0.5
: mostrará segundos contando, pero ocasionalmente saltará más de un segundo. Ejecutarlo como sewatch -n 1 -p sleep 0.5
generará dos veces por segundo, cada segundo, y no verá ningún salto.fuente
Ejecutar las operaciones en una subshell que se ejecuta como un trabajo en segundo plano haría que no interfieran tanto con el
sleep
.El único momento "robado" de un segundo sería el tiempo que lleva lanzar el subshell, por lo que eventualmente se saltará un segundo, pero con suerte con menos frecuencia que el código original.
Si el código en el subshell termina usando más de un segundo, el ciclo comenzará a acumular trabajos en segundo plano y, finalmente, se quedarán sin recursos.
fuente
Otra alternativa (si no puede usar, por ejemplo,
watch -p
como sugiere Maelstrom) essleepenh
[página de manual ], que está diseñada para esto.Ejemplo:
Tenga
sleep 0.2
en cuenta que allí se simula hacer una tarea que consume mucho tiempo comiendo alrededor de 200 ms. A pesar de eso, la salida en nanosegundos se mantiene estable (bueno, según los estándares del sistema operativo que no es en tiempo real); ocurre una vez por segundo:Eso es menos de 1 ms diferente, y no hay tendencia. Eso es bastante bueno; debe esperar rebotes de al menos 10 ms si hay alguna carga en el sistema, pero aún así no hay deriva con el tiempo. Es decir, no perderás ni un segundo.
fuente
Con
zsh
:Si su sueño no admite segundos de coma flotante, puede usar
zsh
'szselect
en su lugar (después de azmodload zsh/zselect
):Esos no deberían derivar mientras los comandos en el bucle tarden menos de un segundo en ejecutarse.
fuente
Tenía exactamente el mismo requisito para un script de shell POSIX, donde todos los ayudantes (usleep, GNUsleep, sleepenh, ...) no están disponibles.
ver: https://stackoverflow.com/a/54494216
fuente