2009-09-10 15 views
5

Niedawno zacząłem uczyć się Pythona, a część prostej aplikacji, którą robię, zawiera zegar z wyświetlaniem hh: mm: ss w swoim wątku.Python sched.scheduler przekracza maksymalną głębokość rekurencji

Rozglądając się po internecie znalazłem dwa sposoby realizacji tego:

  1. Korzystanie sched.scheduler
  2. Korzystanie threading.Timer

Sposób Zrobiłem to wygląda podobnie dla obu implementacjach:

SCHED:

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. działa dobrze w odniesieniu do materacy prawidłowo, ale generuje następujący błąd po kilku minutach: RuntimeError: maksymalna głębokość rekursji przekroczone. Wiem, że możesz ręcznie zwiększyć maksymalny poziom rekurencji, ale z pewnością nie powinno to być tutaj potrzebne?

  2. Brak błędu, ale czasami sekundy będą pomijane lub nieregularne zaznaczanie.

Czy ktoś może wskazać mi właściwy kierunek postępowania? Dziękuję Ci.

+0

Proszę zaksięgować znaleziony link do używania threading.Timer w ten sposób. –

+0

Twój tytuł pytania jest całkowicie błędny. Masz timer przekraczający głębokość rekursji. Nie sched.scheduler. –

+1

Przepraszam, jeśli nie byłam jasna. Edytowane pytanie. Propozycja użycia timera pochodzi stąd Należy pamiętać, że jestem tylko początkującym i prawdopodobnie mam zły pomysł. – user171331

Odpowiedz

4

Zegar jest wydarzeniem jednorazowym. Nie można wykonać pętli w ten sposób.

Korzystanie z licznika czasu w celu wywołania funkcji, która następnie tworzy inny licznik czasu wywołujący funkcję, która tworzy zegar wywołujący funkcję, która tworzy zegar, ..., musi osiągnąć limit rekursji.

Nie wspomnisz o swoim systemie operacyjnym, ale "pomijanie" lub "tykanie nieregularnie" jest z dwóch powodów.

  1. Państwo komputer jest zajęty i „1 sekunda” oznacza „bardzo blisko do 1 sekundy, w zależności od tego, co jeszcze się dzieje”

  2. Jeśli uruchomić stoper w 0.9999 sekund i odczekać 1 sekundę możesz być na poziomie 1.9999 (rundy do 1) lub 2.00000. Może wydawać się, że duplikuje czas lub pomija czas. Wewnętrzny zegar sprzętowy twojego komputera jest bardzo dokładny, a zaokrąglanie rzeczy do najbliższej drugiej woli (zawsze) prowadzi do zdalnej możliwości duplikowania lub przeskakiwania.

Używaj poprawnie sched. http://docs.python.org/library/sched.html#module-sched

Twój fragment kodu również nie ma sensu dla harmonogramu. Nie trzeba tworzyć nowego obiektu terminarza. Musisz tylko utworzyć nowe zdarzenie wydarzenie.

Przeczytaj http://docs.python.org/library/sched.html#sched.scheduler.enter o tworzeniu nowego zdarzenia dla istniejącej instancji programu planującego.

+1

Dzięki za odpowiedź. Wyjaśniłem pytanie, aby uwzględnić moją implementację schematu i błąd, ale domyślam się, że powód jest taki sam, jaki podałeś dla Timera. Jeśli jednak harmonogram planuje pojedyncze wydarzenie w późniejszym terminie, nadal nie widzę sposobu na uniknięcie ograniczenia rekursji :( – user171331

+0

bardzo jasne wyjaśnienie – DrFalk3n

+0

Oprócz linków do stron z python doc, jaki jest "właściwy kierunek" do przejścia następnie :) – HongboZhu

5

Oto jak zrobić jednorazowe zdarzenie w formie cyklicznej, np.z sched: jeśli funkcja musi utworzyć własne planującego i być jedyną rzeczą, działa na jego wątku:

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) 

Jeśli inne zdarzenia musi być również zaplanowane w tym samym wątku następnie planista musi być wykonane i własnością „gdzie indziej” - w if część powyżej można uzyskać refactored w inny sposób, np:

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) 

Ponownie, oczywiście, jak zawsze z sched, natomiast harmonogram jest uruchomiony, będzie on (a zaplanowane callbacks event) „przejąć "wątek, o którym mowa (więc musisz wydzielić osobny wątek, jeśli jesteś yo potrzebujesz innych rzeczy do zrobienia w tym samym czasie).

Jeśli chcesz użyć tego rodzaju idiomu w wielu funkcjach, możesz go refaktoryzować w dekoratorze, ale to w pewien sposób maskowałoby podstawową prostotę idiomu, więc wolę to proste, jawne użycie. BTW, zauważ, że time.time i time.sleep używają sekund, a nie minut, jako jednostki czasu, więc potrzebujesz 60, a nie jednego, aby wskazać "minutę od teraz" ;-).

+0

Zachowałem sugestię dekoratora – DrFalk3n

Powiązane problemy