Question
J'aimerais pouvoir exécuter une commande UNIX précisément chaque seconde sur une longue période .
J'ai besoin d'une solution qui ne tarde pas après un certain temps, à cause du temps nécessaire à l'exécution de la commande elle-même. dormir , regarder , et un certain script python m'a tous échoué à cet égard.
Sur le microcontrôleur tel que le http://Arduino.cc, je le ferais par le biais d'interruptions d'horloge matérielle. Je voudrais savoir s'il existe une solution similaire de script de shell avec précision dans le temps. Toutes les solutions que j'ai trouvées dans StackExchange.com ont entraîné un décalage perceptible, si elles duraient plusieurs heures. Voir les détails ci-dessous.
But pratique / application
Je veux tester si ma connexion réseau est en permanence en hausse en envoyant des horodatages via nc
(netcat) toutes les secondes.
Expéditeur:
precise-timestamp-generator | tee netcat-sender.txt | nc $receiver $port
Receveur:
nc -l -p $port > netcat-receiver.txt
Une fois l’opération terminée, comparez les deux journaux:
diff netcat-sender.txt netcat-receiver.txt
Les diffs seraient les horodatages non transmis. De cela, je saurais à quelle heure mon LAN / WAN / ISP crée des problèmes.
Solution SLEEP
while [ true ]; do date "+%Y-%m-%d %H:%M:%S" ; sleep 1; done | tee timelog-sleep.txt
Obtient un certain décalage dans le temps, car la commande dans la boucle prend également un peu de temps.
Précision
cat timelog-sleep.txt
2012-07-16 00:45:16
[...]
2012-07-16 10:20:36
Secondes écoulées: 34520
wc -l timelog-sleep.txt
Lignes dans le fichier: 34243
Précision résumée:
- 34520-34243 = 277 problèmes de synchronisation
- 34520/34243 = 1,008 = 0,8% de réduction
Solution RÉPÉTER PYTHON
Trouvé à: Répéter une commande Unix toutes les x secondes pour toujours
repeat.py 1 "date '+%Y-%m-%d %H:%M:%S'" >> timelog-repeat-py.txt
Censé éviter le décalage horaire, mais ne parvient pas à le faire.
Précision
wc -l timelog-repeat-py.txt
2012-07-16 13:42:44
[...]
2012-07-16 16:45:24
Secondes écoulées: 10960
wc -l timelog-repeat-py.txt
Lignes dans le fichier: 10859
Précision résumée:
- 10960-10859 = 101 problèmes de chronométrage
- 10960/10859 = 1,009 = 0,9% de réduction
Solution MONTRE
watch -n 1 "date '+%Y-%m-%d %H:%M:%S' >> ~/Desktop/timelog-watch.txt"
Précision
wc -l timelog-watch.txt
2012-07-16 11:04:08
[...]
2012-07-16 13:25:47
Secondes écoulées: 8499
wc -l timelog-watch.txt
Lignes dans le fichier: 8366
Précision résumée:
- 8499-8366 = 133 problèmes de synchronisation.
- 8499/8366 = 1.016 = 1.6% de réduction.
nice
le processus qui dort?Réponses:
Comment fonctionne ce script Perl que je viens de fouetter?
Utilisation:
perl timer.pl 1 date '+%Y-%m-%d %H:%M:%S'
Il a fonctionné pendant 45 minutes sans un seul saut, et je pense qu'il continuera de le faire sauf si a) la charge du système devient tellement élevée que fork () prend plus d'une seconde ou b) une seconde intercalaire est insérée.
Cependant, il ne peut pas garantir que la commande s'exécute à la seconde exacte, car il y a une surcharge, mais je doute que ce soit bien pire qu'une solution basée sur des interruptions.
Je l'ai couru pendant environ une heure avec
date +%N
(nanosecondes, extension GNU) et quelques statistiques à ce sujet. Le délai le plus long était de 1 155 microsecondes. Moyenne (moyenne arithmétique) 216 µs, médiane 219 µs, écart-type 42 µs. Il a fonctionné plus rapidement que 270 µs 95% du temps. Je ne pense pas que vous puissiez le battre, sauf avec un programme en C.la source
GNU date
avec+%N
et après seulement 3 minutes , il a lancé cette erreur: laTime::HiRes::sleep(-0.00615549): negative time not invented yet at ~/bin/repeat.pl line 23.
ligne 23 dans mon script enregistré:sleep $start - time();
La
ualarm()
fonction POSIX vous permet de programmer le noyau pour qu'il signale périodiquement votre processus, avec une précision de l'ordre de la microseconde.Fabriquez un programme simple:
Compiler
Ensuite, attachez-le à ce que vous devez faire régulièrement, comme ceci:
la source
-std=c99
, vous ne recevrez pas d'avertissement concernant le retour manquant. Sinon, vous ne devriez pas avoir besoin de quelque chose de spécial. Avez-vous mal saisi un zéro supplémentaire?strace ./tick
va vous montrer ce qu'il fait d'un point de vue systémiqueAvez-vous essayé
watch
avec le paramètre--precise
?De la page de manuel:
Le paramètre peut ne pas être disponible sur votre système, cependant.
Vous devez également envisager ce qui devrait se passer lorsque l'exécution de votre programme nécessite plus d'une seconde. La prochaine exécution planifiée doit-elle être ignorée ou doit-elle être retardée?
Mise à jour : j'ai exécuté le script pendant un certain temps, et il n'a pas perdu une seule étape:
Mise à jour: le
--precise
drapeau est un ajout de Debian, le correctif est cependant assez simple: http://patch-tracker.debian.org/patch/series/view/procps/1:3.2.8-9squeeze1/watch_precision_time.patchla source
watch
prend en charge cette option? Ce n'était sur aucune des machines que j'ai vérifiées.--precise
. Ceci est un ajout 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
le contenu en temps réel (noyau, etc.) est là pour une raison!crontab
a une résolution de 1 minute. Si le temps de latence s’accumule par minute et s’initialise à la minute suivante, cette idée de base peut fonctionner:Notez qu'il
script.sh
est également exécuté en arrière-plan. Cela devrait aider à minimiser le décalage qui s’accumule à chaque itération de la boucle.En fonction du retard
sleep
généré, il est toutefois possible que le second 59 se chevauche avec le second 0 de la minute suivante.EDIT pour ajouter des résultats, dans le même format que dans la question:
1 heure 52 minutes = 6720 secondes
0 problème de chronométrage, 0% de réduction. Toute accumulation de temps est réinitialisée toutes les minutes.
la source
cron
soit précis à la seconde près, mais ce n'est pas le cas en général.Votre problème est que vous dormez pendant un certain temps après avoir exécuté votre programme sans tenir compte du temps écoulé depuis votre dernier sommeil.
Vous pouvez le faire, bash ou n’importe quel autre langage de programmation, mais la clé consiste à utiliser l’horloge pour déterminer la durée de la prochaine mise en veille. Avant de dormir, observez l'horloge, voyez combien de temps il vous reste et dormez la différence.
En raison de compromis en matière de planification des processus, il n'est pas garanti que vous vous réveilliez au même moment, mais vous devriez être assez proche (pas de charge de quelques ms ou moins de quelques centaines de ms sous charge). Et vous n'accumulerez pas d'erreur au fil du temps, car chaque fois que vous vous resynchronisez à chaque cycle de veille et supprimez toute erreur accumulée.
Si vous avez exactement besoin de l’horloge, vous recherchez un système d’exploitation en temps réel , conçu précisément à cet effet.
la source
date +%S.%N
pour obtenir le nombre de secondes avec une précision inférieure à la seconde etusleep
dormir avec une précision inférieure à une seconde, mais après cela, ce n’est qu’une question de calcul.J'ai toujours juste renoncé à faire fonctionner quelque chose exactement à intervalle. Je pense que vous devrez écrire un programme C et faire très attention à ne pas dépasser la partie de l'intervalle d'une seconde avec votre propre code. Vous devrez probablement utiliser des threads ou plusieurs processus inter-communicants pour que cela fonctionne. Veillez à éviter les temps supplémentaires de démarrage du processus ou du processus.
Une référence qui semble pertinente date de 1993: une horloge d'échantillonnage aléatoire pour l'estimation de l'utilisation de la CPU et le profilage du code. Vous voudrez jeter un coup d'œil à l'annexe "Code source de l'adversaire" pour voir comment ils ont mesuré avec précision les intervalles de temps et se "réveiller". leur programme au bon moment. Comme le code a 19 ans, il ne portera probablement pas directement ou facilement, mais si vous le lisez et essayez de le comprendre, les principes en jeu pourraient guider votre code.
EDIT: trouvé une autre référence qui pourrait aider: Effets de la résolution d'horloge sur la planification de processus interactifs et de processus en temps réel souples Cela devrait vous aider pour n'importe quel fond théorique.
la source
Jetez un coup d’oeil à nanosleep () (à partir de http://linux.about.com/library/cmd/blcmdl2_nanosleep.htm ). Au lieu de laisser votre programme dormir 1 seconde, laissez-le dormir (1 - il faut courir) secondes. Vous obtiendrez une bien meilleure résolution.
la source
sleep
, c.-à-dsleep 0.99
. Le problème est que la durée d'exécution est loin d'être constante, même si sa valeur moyenne peut fluctuer dans le temps.Essayez d’exécuter votre commande en arrière-plan pour ne pas trop affecter le minutage de la boucle, mais même cela ne suffira pas si vous ne voulez pas d’accumulation pendant de longues périodes, car il en coûte sûrement quelques millisecondes.
Donc, c’est probablement mieux, mais aussi probablement pas assez bon:
Sur mon ordinateur, cela donnait 2 erreurs en 20 minutes, soit 0,1 par minute, ce qui représente une amélioration cinq fois moins importante que votre course.
la source
sleep 1
c'est qu'il est garanti de dormir au moins une seconde, jamais moins. Par conséquent l'erreur s'accumule.Moche mais ça marche. Vous devriez probablement repenser la conception de votre programme si vous avez besoin d'une boucle comme celle-ci. Il vérifie fondamentalement si la seconde entière est égale à la précédente et affiche le nombre de nanosecondes depuis le changement de seconde. La précision est influencée par le sommeil .001.
La précision est de l'ordre de la milliseconde, à condition que la "charge utile"
date "+%N nanoseconds late"
ne prenne pas plus longtemps qu'un peu moins d'une seconde. Vous pouvez réduire la charge du processeur en augmentant la période de veille ou, si cela ne vous dérange pas, remplacez simplement la commande de veille partrue
.C'est une mauvaise pratique car vous faites en sorte que l'unité centrale interroge un événement et que vous gaspillez des cycles de l'unité centrale. Vous voudrez probablement vous associer à une interruption de la minuterie (ce qui n'est pas possible à partir de bash) ou utiliser un matériel dédié tel qu'un microcontrôleur. Un PC et son système d'exploitation ne sont pas conçus pour une précision de synchronisation élevée.
la source
Une autre méthode consisterait à utiliser une suspension dans une boucle et à envoyer SIGCONT à partir d’un programme externe précis. L'envoi d'un signal est très léger et aura beaucoup moins de temps de latence que l'exécution de quelque chose. Vous pouvez également pré-mettre en file d'attente un tas de commandes avec la commande "at", presque personne n'utilise "at". Je ne suis pas sûr de sa précision.
Si la précision est essentielle et que vous souhaitez prendre au sérieux ce problème, cela ressemble au type d'application où vous utiliseriez généralement le RTOS, ce qui pourrait être fait sous Linux avec le noyau patché RT-Preempt, qui vous donnera la précision et une certaine mesure de interrompez le contrôle, mais cela risque d’être plus ennuyeux que ça vaut la peine.
https://rt.wiki.kernel.org/index.php/RT_PREEMPT_HOWTO
Xenomai pourrait également être utile, il s’agit d’une implémentation RTOS complète et est porté pour x86 et x86_64, mais une certaine programmation est nécessaire.
http://www.xenomai.org/index.php/Main_Page
la source
Avec
ksh93
(qui a une virgule flottante$SECONDS
et une construitsleep
)Le même script fonctionnera
zsh
également mais invoquera lasleep
commande de votre système .zsh
azselect
intégré, mais avec une résolution de 1/100 seulement.la source
J'irais avec un petit programme C:
Ce programme s'attend à ce que le programme appelle avec le chemin complet comme premier argument et transmet tous les arguments restants. Il n'attendra pas que la commande se termine, il lancera donc plusieurs instances avec plaisir.
De plus, le style de codage est vraiment bâclé, et un certain nombre d’hypothèses sont émises qui peuvent ou non être garanties par les normes applicables, c’est-à-dire que la qualité de ce code est "fonctionne pour moi".
Ce programme aura des intervalles un peu plus longs ou plus courts lorsque l’horloge sera ajustée par NTP ou en la réglant manuellement. Si le programme doit gérer cela, POSIX fournit
timer_create(CLOCK_MONOTONIC, ...)
ce qui n’est pas affecté par cela.la source
Vous devriez garder une trace de l'heure actuelle et la comparer à l'heure de début. Donc, vous dormez une quantité de temps calculée à chaque itération, pas un montant fixe. De cette façon, vous n'accumulerez pas d'erreurs de chronométrage et ne vous éloignerez pas de l'endroit où vous devriez être, car vous réinitialisez chaque chronométrage de chaque boucle en temps absolu à partir du début.
De plus, certaines fonctions de veille reviennent tôt en cas d'interruption. Dans ce cas, vous devrez rappeler votre méthode de veille jusqu'à la fin du temps imparti.
la source
En voici un qui est un script bash et extrêmement précis. Il utilise usleep pour une précision à la microseconde.
http://wiki.junkemailfilter.com/index.php/How_to_run_a_Linux_script_every_few_seconds_under_cron
Il y a 3 scripts ici. Regardez celui en bas. Fera jusqu'à environ 2400 exécutions par minute avec une précision raisonnable. Et c'est vraiment simple.
la source
Celui-ci peut fonctionner au moins 100 fois par seconde avec une résolution très précise.
L’existence du répertoire du nombre de boucles par minute crée le programme. Cette version prend en charge la résolution microseconde en supposant que votre ordinateur puisse le gérer. Le nombre d'exécutions par minute ne doit pas être divisible par 60. Il n'est pas non plus limité à 60. Je l'ai testé à 6000 et cela fonctionne.
Cette version peut être installée dans le répertoire /etc/init.d et exécutée en tant que service.
la source