459 votes

Comment exécuter une fonction de manière répétée toutes les x secondes ?

Je veux exécuter une fonction en Python de manière répétée toutes les 60 secondes pour toujours (comme un NSTimer en Objective C ou setTimeout en JS). Ce code s'exécute comme un démon et revient à appeler le script python script toutes les minutes à l'aide d'un cron, mais sans que l'utilisateur n'ait à le configurer.

En cette question sur un cron implémenté en Python la solution semble en fait se résumer à sleep() pendant x secondes. Je n'ai pas besoin d'une fonctionnalité aussi avancée, alors peut-être que quelque chose comme ceci fonctionnerait

while True:
    # Code executed here
    time.sleep(60)

Ce code pose-t-il des problèmes prévisibles ?

155 votes

Un point pédant, mais qui peut être critique, votre code ci-dessus ne s'exécute pas toutes les 60 secondes, il met un écart de 60 secondes entre les exécutions. Il ne s'exécute toutes les 60 secondes que si le code exécuté ne prend pas de temps du tout.

0 votes

7 votes

Également time.sleep(60) peut revenir plus tôt et plus tard

369voto

nosklo Points 75862

Si votre programme ne dispose pas déjà d'une boucle d'événements, utilisez la fonction calendrier qui met en œuvre un planificateur d'événements à usage général.

import sched, time
s = sched.scheduler(time.time, time.sleep)
def do_something(sc): 
    print("Doing stuff...")
    # do your stuff
    sc.enter(60, 1, do_something, (sc,))

s.enter(60, 1, do_something, (s,))
s.run()

Si vous utilisez déjà une bibliothèque de boucles d'événements comme asyncio , trio , tkinter , PyQt5 , gobject , kivy et bien d'autres - il suffit de planifier la tâche en utilisant les méthodes de votre bibliothèque de boucles d'événements existante.

27 votes

Le module sched est destiné à programmer l'exécution de fonctions après un certain temps, comment l'utiliser pour répéter l'appel d'une fonction toutes les x secondes sans utiliser time.sleep() ?

2 votes

@Baishampayan : Il suffit de programmer une nouvelle course.

0 votes

Kronos, basé sur sched, offre une interface de plus haut niveau : razorvine.net/download/kronos.py Utilisé par TurboGears.

85voto

Aaron Maenpaa Points 39173

Vous pouvez envisager Torsadé qui est une bibliothèque de réseau Python qui met en œuvre la fonction Modèle de réacteur .

from twisted.internet import task, reactor

timeout = 60.0 # Sixty seconds

def doWork():
    #do work here
    pass

l = task.LoopingCall(doWork)
l.start(timeout) # call every sixty seconds

reactor.run()

Alors que "while True : sleep(60)" fonctionnera probablement Twisted implémente déjà plusieurs des fonctionnalités dont vous aurez éventuellement besoin (daemonization, logging ou gestion des exceptions comme l'a souligné bobince) et sera probablement une solution plus robuste.

0 votes

Excellente réponse également, très précise sans dérive. Je me demande si cela met également le CPU en veille pendant qu'il attend d'exécuter la tâche (c'est-à-dire qu'il n'est pas occupé à attendre) ?

2 votes

Cette dérive est de l'ordre de la milliseconde

1 votes

Que signifie "dérives au niveau de la milliseconde" ?

35voto

Itxaka Points 304

Je pense que la solution la plus simple est la suivante :

import time

def executeSomething():
    #code here
    time.sleep(60)

while True:
    executeSomething()

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

55 votes

En fait, ce n'est pas la réponse : time sleep() ne peut être utilisé que pour attendre X secondes après chaque exécution. Par exemple, si votre fonction prend 0,5 seconde pour s'exécuter et que vous utilisez time.sleep(1), cela signifie que votre fonction s'exécute toutes les 1,5 secondes, et non 1. Vous devez utiliser d'autres modules et/ou threads pour vous assurer que quelque chose fonctionne Y fois par X secondes.

1 votes

@kommradHomer : Réponse de Dave Rove démontre que vous peut utilice time.sleep() exécuter quelque chose toutes les X secondes

2 votes

À mon avis, le code devrait appeler time.sleep() en while True boucle comme : def executeSomething(): print('10 sec left') ; while True: executeSomething(); time.sleep(10)

6voto

Anay Points 49

J'ai été confronté à un problème similaire il y a quelque temps. Il se peut que http://cronus.readthedocs.org pourrait aider ?

Pour la version 0.2, l'extrait suivant fonctionne

import cronus.beat as beat

beat.set_rate(2) # 2 Hz
while beat.true():
    # do some time consuming work here
    beat.sleep() # total loop duration would be 0.5 sec

5voto

bobince Points 270740

La principale différence avec cron est qu'une exception tue le démon pour de bon. Vous pourriez vouloir utiliser un collecteur d'exceptions et un enregistreur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X