2012-03-21 66 views
23

Próbuję napisać metodę, która odlicza do określonego czasu i jeśli polecenie restartu nie zostanie podane, wykona to zadanie. Ale nie sądzę, że klasa Python threading.Timer pozwala na anulowanie timera.Anulowanie wątków.Timer w Pythonie

import threading 

def countdown(action): 
    def printText(): 
     print 'hello!' 

    t = threading.Timer(5.0, printText) 
    if (action == 'reset'): 
     t.cancel() 

    t.start() 

Wiem, że powyższy kod jest nieprawidłowy. Byłbym wdzięczny za pewne wskazówki tutaj.

Odpowiedz

12

Nie jestem pewien, czy rozumiem poprawnie. Czy chcesz napisać coś jak w tym przykładzie?

>>> import threading 
>>> t = None 
>>> 
>>> def sayHello(): 
...  global t 
...  print "Hello!" 
...  t = threading.Timer(0.5, sayHello) 
...  t.start() 
... 
>>> sayHello() 
Hello! 
Hello! 
Hello! 
Hello! 
Hello! 
>>> t.cancel() 
>>> 
+0

To jest prawie najlepsze. Byłoby * dobrze *, gdyby twój program nie zakończył się natychmiast, z pojedynczym "Cześć" i bez żadnego opóźnienia! :) Musisz włączyć 't.cancel()' do funkcji 'sayHello()' w oparciu o pewne warunki, np. 'jeśli licznik == 10: t.cancel()'. Miałoby to wtedy znaczenie. – Apostolos

+0

Przepraszamy. Wówczas nawet nie byłby dobry. Jeśli dodasz dowolny kod po wywołaniu 'sayHello (0)', zostanie ono wykonane przed zakończeniem testu timera! (Wypróbuj sam, dodając np. 'Print" Zrobione "' na końcu twojego kodu.) – Apostolos

25

by wywołać metodę odwołać po uruchomieniu Timer:

import time 
import threading 

def hello(): 
    print "hello, world" 
    time.sleep(2) 

t = threading.Timer(3.0, hello) 
t.start() 
var = 'something' 
if var == 'something': 
    t.cancel() 

Można rozważyć zastosowanie chwilę pętli na Thread, zamiast korzystania z timer.
Oto przykład przywłaszczył od Nikolaus Gradwohl na answer do innego pytania:

import threading 
import time 

class TimerClass(threading.Thread): 
    def __init__(self): 
     threading.Thread.__init__(self) 
     self.event = threading.Event() 
     self.count = 10 

    def run(self): 
     while self.count > 0 and not self.event.is_set(): 
      print self.count 
      self.count -= 1 
      self.event.wait(1) 

    def stop(self): 
     self.event.set() 

tmr = TimerClass() 
tmr.start() 

time.sleep(3) 

tmr.stop() 
+0

Proszę wyjaśnij, dlaczego uważasz, że pętla czasowa jest lepszym pomysłem niż gwintowany zegar. –

+1

@WesModes Zaproponowałem alternatywę, która drukuje odliczanie. –

+0

Działa dla mnie. Chociaż użyłem, a nie self.event.wait (1), aby wykonać coś co sekundę zamiast zmiennej licznika – mtosch

6

threading.Timer klasa ma mieć metodę cancel, a mimo to nie anuluje wątekbędzie zatrzymać stoper od faktycznie strzelania. W rzeczywistości metoda threading.Event ustawia threading.Event, a wątek faktycznie wykonujący threading.Timer sprawdzi to zdarzenie po zakończeniu oczekiwania i zanim faktycznie wykona wywołanie zwrotne.

To powiedziawszy, zegary są zwykle realizowane bez za pomocą osobnego wątku dla każdego. Najlepszy sposób na zrobienie tego zależy od tego, co faktycznie robi twój program (podczas czekania na ten timer), ale wszystko z pętlą zdarzeń, takie jak GUI i struktury sieciowe, wszystkie mają sposoby na żądanie zegara, który jest podłączony do pętli zdarzeń.

0

Zainspirowany powyższym wpisie. Anulowanie i resetowanie timera w języku Python. Używa wątku.
Funkcje: Uruchom, Zatrzymaj, Uruchom ponownie, funkcja oddzwaniania.
Wejście: Limit czasu, wartości sleep_chunk i funkcja callback.
Może używać tej klasy lub dziedziczyć ją w dowolnym innym programie. Potrafi również przekazywać argumenty do funkcji wywołania zwrotnego.
Zegar powinien reagować również w środku. Nie tylko po zakończeniu pełnego snu. Więc zamiast używać jednego pełnego snu, używając małych fragmentów snu i utrzymywano sprawdzanie obiektu zdarzenia w pętli.

import threading 
import time 

class TimerThread(threading.Thread): 
    def __init__(self, timeout=3, sleep_chunk=0.25, callback=None, *args): 
     threading.Thread.__init__(self) 

     self.timeout = timeout 
     self.sleep_chunk = sleep_chunk 
     if callback == None: 
      self.callback = None 
     else: 
      self.callback = callback 
     self.callback_args = args 

     self.terminate_event = threading.Event() 
     self.start_event = threading.Event() 
     self.reset_event = threading.Event() 
     self.count = self.timeout/self.sleep_chunk 

    def run(self): 
     while not self.terminate_event.is_set(): 
      while self.count > 0 and self.start_event.is_set(): 
       # print self.count 
       # time.sleep(self.sleep_chunk) 
       # if self.reset_event.is_set(): 
       if self.reset_event.wait(self.sleep_chunk): # wait for a small chunk of timeout 
        self.reset_event.clear() 
        self.count = self.timeout/self.sleep_chunk # reset 
       self.count -= 1 
      if self.count <= 0: 
       self.start_event.clear() 
       #print 'timeout. calling function...' 
       self.callback(*self.callback_args) 
       self.count = self.timeout/self.sleep_chunk #reset 

    def start_timer(self): 
     self.start_event.set() 

    def stop_timer(self): 
     self.start_event.clear() 
     self.count = self.timeout/self.sleep_chunk # reset 

    def restart_timer(self): 
     # reset only if timer is running. otherwise start timer afresh 
     if self.start_event.is_set(): 
      self.reset_event.set() 
     else: 
      self.start_event.set() 

    def terminate(self): 
     self.terminate_event.set() 

#================================================================= 
def my_callback_function(): 
    print 'timeout, do this...' 

timeout = 6 # sec 
sleep_chunk = .25 # sec 

tmr = TimerThread(timeout, sleep_chunk, my_callback_function) 
tmr.start() 

quit = '0' 
while True: 
    quit = raw_input("Proceed or quit: ") 
    if quit == 'q': 
     tmr.terminate() 
     tmr.join() 
     break 
    tmr.start_timer() 
    if raw_input("Stop ? : ") == 's': 
     tmr.stop_timer() 
    if raw_input("Restart ? : ") == 'r': 
     tmr.restart_timer() 
Powiązane problemy