2009-09-10 8 views
5

J'ai récemment commencé à apprendre Python et une partie de l'application simple que je fais inclut une minuterie avec un affichage hh: mm: ss fonctionnant dans son propre thread.Python sched.scheduler dépasse la profondeur de récursivité maximale

regardant autour du web j'ai trouvé deux façons de mettre en œuvre cette:

  1. Utilisation sched.scheduler
  2. Utilisation threading.Timer

La façon dont je l'ai fait, il semble similaire pour les deux mises en œuvre:

Serv:

def tick(self, display, alarm_time): 

    # Schedule this function to run every minute 
    s = sched.scheduler(time.time, time.sleep) 
    s.enter(1, 1, self.tick, ([display, alarm_time])) 

    # Update the time 
    self.updateTime(display) 

Timer:

def tick(self, display): 

    # Schedule this function to run every second 
    t = Timer(1, self.tick, (display,alarm_time)) 
    t.start() 

    # Update the time 
    self.updateTime(display) 
  1. fonctionne très bien en ce qui concerne tic-tac correctement, mais génère l'erreur suivante après quelques minutes: RuntimeError: profondeur de récursivité maximale dépassée. Je sais que vous pouvez augmenter le niveau de récurrence max manuellement, mais cela ne devrait sûrement pas être nécessaire ici?

  2. Pas d'erreur, mais occasionnellement, les secondes sautent ou cochent de manière irrégulière.

Quelqu'un peut-il me diriger dans la bonne direction sur la façon de le faire correctement? Je vous remercie.

+0

S'il vous plaît poster le lien que vous avez trouvé pour l'utilisation de threading.Timer comme ça. –

+0

Le titre de votre question est complètement faux. Vous avez Minuterie dépassant la profondeur de récursivité. Pas sched.scheduler. –

+1

Désolé si je n'étais pas clair. Question éditée La suggestion d'utiliser Timer vient d'ici S'il vous plaît gardez à l'esprit que je suis juste un débutant et probablement eu une mauvaise idée. – user171331

Répondre

4

Un temporisateur est un événement ponctuel. Il ne peut pas être fait en boucle de cette façon. L'utilisation d'un temporisateur pour appeler une fonction qui crée alors une autre temporisation qui appelle une fonction créant un temporisateur qui appelle une fonction qui crée un temporisateur, ..., doit atteindre la limite de récurrence.

Vous ne mentionnez pas votre système d'exploitation, mais "sauter" ou "cocher irrégulièrement" est pour deux raisons.

  1. Votre ordinateur est occupé et « 1 seconde » signifie « assez proche de 1 seconde, en fonction de ce qu'il se passe »

  2. Si vous démarrez votre minuterie à 0,9999 secondes, et attendez 1 seconde , vous pourriez être à 1.9999 (arrondit à 1) ou 2.00000. Il peut sembler dupliquer une heure ou passer une heure. L'horloge matérielle interne de votre ordinateur est très précise, et arrondir les éléments à la seconde près conduira (toujours) à la possibilité de doublons ou de sauts.

Utilisez sched correctement. http://docs.python.org/library/sched.html#module-sched

Votre extrait de code n'a aucun sens pour sched non plus. Vous n'avez pas besoin de créer un nouvel objet de planificateur. Vous avez seulement besoin de créer un nouvel événement .

Lecture http://docs.python.org/library/sched.html#sched.scheduler.enter lors de la création d'un nouvel événement pour une instance de planificateur existante.

+1

Merci pour votre réponse. J'ai clarifié la question pour inclure mon implémentation de sched et l'erreur, mais je devine que la raison est la même que celle que vous avez donnée pour Timer. Toutefois, si sched ne planifie qu'un seul événement à une date ultérieure, je ne vois toujours pas comment éviter la limite de récursivité :( – user171331

+0

explication très claire – DrFalk3n

+0

Autre que des liens vers des pages doc python, quelle est la "bonne direction" à parcourir alors :) – HongboZhu

5

Voici comment faire un one-shot dans un événement périodique, par ex.avec sched: si la fonction doit faire son propre planificateur et être la seule chose en cours d'exécution sur le fil:

def tick(self, display, alarm_time, scheduler=None): 
    # make a new scheduler only once & schedule this function immediately 
    if scheduler is None: 
    scheduler = sched.scheduler(time.time, time.sleep) 
    scheduler.enter(0, 1, self.tick, ([display, alarm_time, scheduler])) 
    scheduler.run() 

    # reschedule this function to run again in a minute 
    scheduler.enter(1, 1, self.tick, (display, alarm_time, scheduler])) 

    # do whatever actual work this function requires, e.g.: 
    self.updateTime(display) 

Si d'autres événements doivent également être programmées dans le même thread alors le planificateur doit être faite et la propriété « ailleurs » - la partie if ci-dessus peut se refondus dans une autre méthode, par exemple:

def scheduleperiodic(self, method, *args): 
    self.scheduler = sched.scheduler(time.time, time.sleep) 
    self.scheduler.enter(0, 1, method, args) 
    # whatever else needs to be scheduled at start, if any, can go here 
    self.scheduler.run() 

def tick(self, display, alarm_time): 
    # reschedule this function to run again in a minute 
    self.scheduler.enter(60, 1, self.tick, (display, alarm_time)) 

    # do whatever actual work this function requires, e.g.: 
    self.updateTime(display) 

Encore une fois, bien sûr, et comme toujours avec sched, alors que le planificateur est en cours d'exécution, (et les rappels d'événements programmés) « prendra plus "le fil en question (donc vous aurez besoin de rincer un fil séparé pour cela si vous vous avez besoin d'autres choses qui se passent en même temps). Si vous avez besoin d'utiliser ce type d'idiome dans de nombreuses fonctions, il pourrait être refactorisé dans un décorateur, mais cela masquerait quelque peu la simplicité sous-jacente de l'idiome, donc je préfère cette utilisation simple et ouverte. BTW, notez que time.time et time.sleep utilisent les secondes, pas les minutes, comme leur unité de temps, donc vous avez besoin de 60, pas un, pour indiquer "une minute à partir de maintenant" ;-).

+0

J'ai gardé la suggestion pour un décorateur – DrFalk3n

Questions connexes