2010-02-08 15 views
50

Chcę uruchomić funkcję co 60 sekund na Pythonie, ale nie chcę być blokowana w międzyczasie.Jak wykonać funkcję asynchronicznie co 60 sekund w Pythonie?

Jak mogę to zrobić asynchronicznie?

import threading 
import time 

def f(): 
    print("hello world") 
    threading.Timer(3, f).start() 

if __name__ == '__main__': 
    f()  
    time.sleep(20) 

Za pomocą tego kodu funkcja f jest wykonywana co 3 sekundy w ciągu 20 sekund. Na koniec daje błąd i myślę, że to dlatego, że threading.timer nie został anulowany.

Jak mogę to anulować?

Z góry dziękuję!

+0

Twój program kończy działanie po utworzeniu pierwszego licznika czasu. –

+0

Aby anulować Timer, musisz mieć gdzieś odniesienie i wywołać jego metodę "cancel". –

+0

Należy zauważyć, że wszystkie opublikowane do tej pory rozwiązania cierpią na (małe) skumulowane narastanie błędu. To znaczy, zamiast obliczać następny czas snu w oparciu o ustalony czas rozpoczęcia, po prostu śpią dla "kolejnych 60.". To nigdy nie spać przez mniej niż 60s, i zwykle spać przez nieco więcej niż 60s. Nie zawsze jest to problem, ale jeśli chcesz spać dokładnie 1440 razy dziennie, upewnij się, że zrekompensowałeś ten błąd. –

Odpowiedz

87

można spróbować klasę threading.Timer: http://docs.python.org/library/threading.html#timer-objects.

import threading 

def f(f_stop): 
    # do something here ... 
    if not f_stop.is_set(): 
     # call f() again in 60 seconds 
     threading.Timer(60, f, [f_stop]).start() 

f_stop = threading.Event() 
# start calling f now and every 60 sec thereafter 
f(f_stop) 

# stop the thread when needed 
#f_stop.set() 
+0

z tym kodem, który wykonuje tylko jeden raz, czy czegoś brakuje, aby wykonać więcej razy? –

+3

Musisz '.start()' Timer, edytowałem go. –

+0

Ups, dzięki za dodanie .start() ... powinienem był skopiować/wkleić od mojego tłumacza :). Teraz powinno się go wywoływać co 60 sekund, a nie tylko raz. –

0

Dlaczego nie stworzyć specjalny wątek, w którym można umieścić prostą pętlę spania:

#!/usr/bin/env python 
import time 
while True: 
    # Your code here 
    time.sleep(60) 
+7

To nie jest Python. –

+1

Nie, ale taki jest pomysł. Kiedy odpowiedziałem, nie było kodu, więc to był tylko pomysł. – Aif

+0

@MikeGraham Czy możesz wyjaśnić, dlaczego nie jest to Python? – Dunatotatos

2

Najprostszym sposobem jest utworzenie wątku tła działającego co 60 sekund. Trywialny realizacja jest:

class BackgroundTimer(Thread): 
    def run(self): 
     while 1: 
     Time.sleep(60) 
     # do something 


# ... SNIP ... 
# Inside your main thread 
# ... SNIP ... 

timer = BackgroundTimer() 
timer.start() 

Oczywiście, jeśli „coś zrobić” trwa długo, trzeba dostosować do niego w swoim oświadczeniu uśpienia. Jest to jednak dobre przybliżenie.

+0

Mam nadzieję, że zdajesz sobie sprawę, że pusta metoda "__init__" jest zbędna :) –

+0

Oczywiście ... naprawiono :-) Dzięki. – 0xfe

+0

Sposób na uniezależnienie się od czasu wykonania polega na użyciu zegara czasu rzeczywistego (np. 'Time.time()' lub 'datetime.teraz() '), sprawdź czas na początku wykonywania zadania, dodaj 60 sekund, aby uzyskać czas na następne wystrzelenie, następnie sprawdź ponownie na końcu i odejmij od następnego czasu wystrzelenia, aby uzyskać czas snu. –

2

To zależy od tego, co faktycznie chcesz zrobić w międzyczasie. Wątki są najbardziej ogólnym i najmniej preferowanym sposobem robienia tego; powinieneś zdawać sobie sprawę z problemów związanych z wątkami, gdy go używasz: nie wszystkie kody (poza Pythonem) umożliwiają dostęp z wielu wątków jednocześnie, komunikacja między wątkami powinna odbywać się przy użyciu bezpiecznych struktur danych takich jak Queue.Queue, nie będziesz w stanie przerwać wątek z zewnątrz i zakończyć program, gdy wątek nadal działa, może doprowadzić do zawieszenia tłumacza lub fałszywych tropów.

Często jest łatwiejszy sposób. Jeśli robisz to w programie GUI, użyj funkcji timera lub zdarzenia w bibliotece interfejsu GUI. Wszystkie GUI mają to. Podobnie, jeśli używasz innego systemu zdarzeń, takiego jak Twisted lub inny model procesu serwera, powinieneś być w stanie podłączyć się do głównej pętli zdarzeń, aby regularnie wywoływać twoją funkcję. Podejście nietradycyjne powoduje, że twój program jest blokowany, podczas gdy funkcja jest w toku, ale nie pomiędzy funkcjami.

+0

Pułapkę wykonując to na zegar GUI jest to, że GUI jest zamrożone podczas obsługi limitu czasu. Jeśli zadanie jest krótkie, nie ma problemu. Jeśli nie, twój program wydaje się zawieszać co minutę. –

2

Przeszukałem go i znalazłem framework Python circuits, który pozwala czekać
dla określonego wydarzenia.

.callEvent(self, event, *channels) metoda obwodów zawiera ogień i zawiesić-aż-odpowiedzi funkcjonalność, dokumentacja mówi:

Ogień danego zdarzenia do określonych kanałów i zawiesić wykonywanie dopóki nie został wysłany. Ta metoda może być wywoływana tylko jako argument dla najwyższego poziomu wykonania programu obsługi (na przykład "yield self.callEvent(event)"). Skutecznie tworzy i zwraca generator, który będzie wywoływany przez główną pętlę, dopóki zdarzenie nie zostanie wysłane (patrz: func: circuits.core.handlers.handler).

Mam nadzieję, że to tak dobre, jak to zrobić :)
./regards

+0

Chociaż nieco poza tematem. To doskonały link. – Glycerine

1

Jeśli chcesz wywołać metodę „na zegarze” (na przykład co godzinę na godzinę) można zintegrować następujące pojęcia o cokolwiek gwintowania mechanizm wybrać pomiędzy:

import time 

def wait(n): 
    '''Wait until the next increment of n seconds''' 
    x = time.time() 
    time.sleep(n-(x%n)) 
    print time.asctime() 
1

Myślę, że właściwą drogą do prowadzenia wątku wielokrotnie jest następny:

import threading 
import time 

def f(): 
    print("hello world") # your code here 
    myThread.run() 

if __name__ == '__main__': 
    myThread = threading.Timer(3, f) # timer is set to 3 seconds 
    myThread.start() 
    time.sleep(10) # it can be loop or other time consuming code here 
    if myThread.is_alive(): 
     myThread.cancel() 

Za pomocą tego kodu funkcja f jest wykonywana co 3 sekundy w ciągu 10 sekundowego czasu. (10). Na końcu bieg wątku jest anulowany.

Powiązane problemy