Отменяемые потоки. Таймер в Python - PullRequest
31 голосов
/ 22 марта 2012

Я пытаюсь написать метод, который ведет обратный отсчет до заданного времени и, если не будет дана команда перезапуска, он выполнит задачу. Но я не думаю, что класс Python threading.Timer допускает отмену таймера.

import threading

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

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

    t.start()

Я знаю, что приведенный выше код неверен. Буду признателен за некоторые советы здесь.

Ответы [ 4 ]

32 голосов
/ 22 марта 2012

Вы вызвали бы метод отмены после запуска таймера:

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()

Вы можете рассмотреть возможность использования цикла while в Thread вместоиспользование Таймера .
Вот пример, присвоенный ответа Николая Градвохля на другой вопрос:

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()
13 голосов
/ 22 марта 2012

Я не уверен, правильно ли я понимаю. Вы хотите написать что-то вроде этого примера?

>>> 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()
>>>
7 голосов
/ 22 марта 2012

Класс threading.Timer имеет метод cancel, и хотя он не отменяет поток , он остановит таймер от фактического срабатывания.Что на самом деле происходит, так это то, что метод cancel устанавливает threading.Event, и поток, фактически выполняющий threading.Timer, проверит это событие после завершения ожидания и до того, как он фактически выполнит обратный вызов.

При этомтаймеры обычно реализуются без , используя отдельный поток для каждого.Лучший способ сделать это зависит от того, что на самом деле делает ваша программа (в ожидании этого таймера), но все, что связано с циклом обработки событий, например GUI и сетевые инфраструктуры, все имеют способы запросить таймер, который подключен к eventloop.

0 голосов
/ 03 апреля 2017

Вдохновленный вышеуказанным постом.Таймер отмены и сброса в Python.Он использует thread.
Особенности: Start, Stop, Restart, функция обратного вызова.
Input: Timeout, значения sleep_chunk и callback_function.
Может использовать или наследовать этот класс в любой другой программе.Также может передавать аргументы в функцию обратного вызова.
Таймер должен также отвечать посередине.Не только после завершения полного времени сна.Таким образом, вместо одного полного сна, используя маленькие кусочки сна и продолжая проверять объект события в цикле.

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()
...