Je veux exécuter à plusieurs reprises une fonction en Python toutes les 60 secondes pour toujours (tout comme un NSTimer dans Objective C). Ce code s'exécutera en tant que démon et revient à appeler le script python toutes les minutes à l'aide d'un cron, mais sans exiger qu'il soit configuré par l'utilisateur.
Dans cette question sur un cron implémenté en Python , la solution semble effectivement juste sleep () pendant x secondes. Je n'ai pas besoin de fonctionnalités aussi avancées, alors peut-être que quelque chose comme ça fonctionnerait
while True:
# Code executed here
time.sleep(60)
Y a-t-il des problèmes prévisibles avec ce code?
time.sleep(60)
peut également revenir plus tôt et plus tardRéponses:
Si votre programme n'a pas déjà de boucle d'événement, utilisez le module sched , qui implémente un planificateur d'événements à usage général.
Si vous utilisez déjà une bibliothèque de boucle d'événements comme
asyncio
,trio
,tkinter
,PyQt5
,gobject
,kivy
, et bien d' autres - juste planifier la tâche en utilisant votre méthodes de bibliothèque de boucles d'événements existant, au lieu.la source
enterabs()
pour l'éviter. Voici une version non dérivante pour comparaison .time.sleep
peuvent s'accumuler ici. "exécuter toutes les X secondes" et "exécuter avec un retard de ~ X secondes à plusieurs reprises" ne sont pas les mêmes. Voir aussi ce commentaireVerrouillez votre boucle temporelle sur l'horloge système comme ceci:
la source
twisted
réponse sont les seules réponses qui exécutent une fonction toutes lesx
secondes. Les autres exécutent la fonction avec un délai dex
quelques secondes après chaque appel.from time import time, sleep
cause des implications existentielles;)starttime
si vous commencez par le synchroniser à un certain moment: celatime.sleep(60 - time.time() % 60)
a bien fonctionné pour moi. Je l'ai utilisé commetime.sleep(1200 - time.time() % 1200)
et il me donne des journaux sur le:00 :20 :40
, exactement comme je le voulais.sleep()
, latimer()
précision et le temps qu'il faut pour exécuter le corps de la boucle , mais sur des itérations moyennes toujours se produire sur les limites d' intervalle (même si certains sont ignorés):while keep_doing_it(): sleep(interval - timer() % interval)
. Comparez-le avec celuiwhile keep_doing_it(): sleep(interval)
où les erreurs peuvent s'accumuler après plusieurs itérations.Vous voudrez peut-être considérer Twisted qui est une bibliothèque de mise en réseau Python qui implémente le modèle de réacteur .
Alors que "while True: sleep (60)" fonctionnera probablement, Twisted implémente probablement déjà la plupart des fonctionnalités dont vous aurez éventuellement besoin (démonisation, journalisation ou gestion des exceptions comme indiqué par bobince) et sera probablement une solution plus robuste
la source
Si vous voulez un moyen non bloquant d'exécuter périodiquement votre fonction, au lieu d'une boucle infinie bloquante, j'utiliserais un minuteur fileté. De cette façon, votre code peut continuer à fonctionner et effectuer d'autres tâches tout en ayant votre fonction appelée toutes les n secondes. J'utilise beaucoup cette technique pour imprimer des informations de progression sur de longues tâches gourmandes en CPU / disque / réseau.
Voici le code que j'ai publié dans une question similaire, avec les contrôles start () et stop ():
Usage:
Fonctionnalités:
start()
etstop()
sont sûrs d'appeler plusieurs fois même si la minuterie a déjà démarré / arrêtéinterval
tout moment, il sera effectif après la prochaine exécution. Pareil pourargs
,kwargs
et mêmefunction
!la source
def _run(self)
Je suis en train d'envelopper ma tête autour de pourquoi vous appelezself.start()
avantself.function()
. Peux-tu élaborer? Je pense qu'en appelant enstart()
premier, il enself.is_running
sera toujoursFalse
ainsi, puis nous ferons toujours tourner un nouveau fil.x
secondes (c.-à-d. T = 0, t = 1x, t = 2x, t = 3x, ...) où, sur les affiches originales, l'exemple de code exécute une fonction avec un intervalle de x seconde entre les deux. De plus, cette solution a, je crois, un bogue si elleinterval
est plus courte que le temps nécessairefunction
à son exécution. Dans ce cas,self._timer
sera écrasé dans lastart
fonction..function()
after.start()
est d'exécuter la fonction à t = 0. Et je ne pense pas que ce sera un problème si celafunction
prend plus de tempsinterval
, mais oui, il pourrait y avoir des conditions de course sur le code.Je pense que la manière la plus simple est:
De cette façon, votre code est exécuté, puis il attend 60 secondes puis il s'exécute à nouveau, attend, exécute, etc ... Pas besoin de compliquer les choses: D
la source
time.sleep()
exécuter quelque chose toutes les X secondestime.sleep()
enwhile True
boucle comme:def executeSomething(): print('10 sec left') ; while True: executeSomething(); time.sleep(10)
Si vous souhaitez le faire sans bloquer votre code restant, vous pouvez l'utiliser pour le laisser s'exécuter dans son propre thread:
Cette solution combine plusieurs fonctionnalités rarement trouvées combinées dans les autres solutions:
threading.Timer
ou autre), cela mettra fin à la chaîne. Aucune autre exécution n'aura lieu alors, même si la raison du problème est déjà corrigée. Une boucle simple et l'attente avec un simplesleep()
est beaucoup plus robuste en comparaison.next_time += delay
place.la source
Voici une mise à jour du code de MestreLion qui évite les dérives au fil du temps.
La classe RepeatedTimer appelle ici la fonction donnée toutes les "intervalles" secondes comme demandé par l'OP; le calendrier ne dépend pas du temps nécessaire à l'exécution de la fonction. J'aime cette solution car elle n'a pas de dépendances de bibliothèques externes; c'est juste du python pur.
Exemple d'utilisation (copié de la réponse de MestreLion):
la source
J'ai fait face à un problème similaire il y a quelque temps. Peut-être que http://cronus.readthedocs.org pourrait vous aider?
Pour la v0.2, l'extrait de code suivant fonctionne
la source
La principale différence entre cela et cron est qu'une exception va tuer le démon pour de bon. Vous voudrez peut-être envelopper avec un capteur et un enregistreur d'exceptions.
la source
Une réponse possible:
la source
J'ai fini par utiliser le module de planification . L'API est sympa.
la source
J'utilise la méthode Tkinter after (), qui ne "vole pas le jeu" (comme le module sched qui a été présenté précédemment), c'est-à-dire qu'elle permet à d'autres choses de fonctionner en parallèle:
do_something1()
etdo_something2()
peut fonctionner en parallèle et à n'importe quelle vitesse d'intervalle. Ici, le 2ème sera exécuté deux fois plus vite. Notez également que j'ai utilisé un simple compteur comme condition pour terminer l'une ou l'autre fonction. Vous pouvez utiliser n'importe quelle autre contition que vous aimez ou aucune si vous avez une fonction à exécuter jusqu'à la fin du programme (par exemple une horloge).la source
after
ne permet pas aux choses de fonctionner en parallèle. Tkinter est un thread unique et ne peut faire qu'une seule chose à la fois. Si quelque chose planifié parafter
s'exécute, il ne s'exécute pas en parallèle avec le reste du code. Si les deuxdo_something1
etdo_something2
sont planifiés pour s'exécuter en même temps, ils s'exécuteront séquentiellement, pas en parallèle.sched
solution et cela fonctionnera exactement de la même manière que la vôtre.Voici une version adaptée au code de MestreLion. En plus de la fonction d'origine, ce code:
1) ajouter first_interval utilisé pour déclencher la minuterie à un moment précis (l'appelant doit calculer le premier_intervalle et passer)
2) résoudre une condition de concurrence dans le code d'origine. Dans le code d'origine, si le thread de contrôle n'a pas réussi à annuler le minuteur en cours d'exécution ("Arrêtez le minuteur et annulez l'exécution de l'action du minuteur. Cela ne fonctionnera que si le minuteur est encore dans sa phase d'attente." Cité de https: // docs.python.org/2/library/threading.html ), le minuteur fonctionnera sans fin.
la source
Cela semble beaucoup plus simple que la solution acceptée - y a-t-il des lacunes que je ne considère pas? Je suis venu ici à la recherche de pâtes à la copie simple et j'ai été déçu.
Qui sort de manière asynchrone.
Cela a une dérive dans le sens où si la tâche en cours d'exécution prend un temps appréciable, alors l'intervalle devient 2 secondes + temps de tâche, donc si vous avez besoin d'une planification précise, ce n'est pas pour vous.
Notez que l'
daemon=True
indicateur signifie que ce thread n'empêchera pas l'application de s'arrêter. Par exemple, avait un problème oùpytest
se bloquerait indéfiniment après avoir exécuté des tests en attendant que cette tête cesse.la source
J'utilise ceci pour provoquer 60 événements par heure avec la plupart des événements se produisant au même nombre de secondes après la minute entière:
Selon les conditions réelles, vous pouvez obtenir des tiques de longueur:
mais au bout de 60 minutes, vous aurez 60 ticks; et la plupart se produiront avec le décalage correct à la minute que vous préférez.
Sur mon système, j'obtiens une dérive typique de <1 / 20ème de seconde jusqu'à ce que le besoin de correction apparaisse.
L'avantage de cette méthode est la résolution de la dérive d'horloge; ce qui peut entraîner des problèmes si vous faites des choses comme ajouter un élément par tick et que vous vous attendez à 60 éléments ajoutés par heure. Le fait de ne pas tenir compte de la dérive peut amener des indications secondaires comme les moyennes mobiles à considérer les données trop profondément dans le passé, ce qui entraîne une sortie défectueuse.
la source
par exemple, afficher l'heure locale actuelle
la source
la source
Voici une autre solution sans utiliser de bibliothèques supplémentaires.
la source