简体   繁体   English

Python 中的可取消 threading.Timer

[英]Cancellable threading.Timer in Python

I am trying to write a method that counts down to a given time and unless a restart command is given, it will execute the task.我正在尝试编写一个倒计时到给定时间的方法,除非给出重新启动命令,否则它将执行任务。 But I don't think Python threading.Timer class allows for timer to be cancelable.但我不认为 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()

I know the above code is wrong somehow.我知道上面的代码不知何故是错误的。 Would appreciate some kind guidance over here.很感激这里的一些指导。

You would call the cancel method after you start the 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()

You might consider using a while-loop on a Thread , instead of using a Timer .您可能会考虑在Thread上使用 while 循环,而不是使用Timer
Here is an example appropriated from Nikolaus Gradwohl's answer to another question:以下是 Nikolaus Gradwohl 对另一个问题的回答中的一个示例:

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

I'm not sure if I understand correctly.我不确定我是否理解正确。 Do you want to write something like in this example?你想在这个例子中写一些类似的东西吗?

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

The threading.Timer class does have a cancel method, and although it won't cancel the thread , it will stop the timer from actually firing. threading.Timer确实有一个cancel方法,虽然它不会取消线程,但它会阻止计时器实际触发。 What actually happens is that the cancel method sets a threading.Event , and the thread actually executing the threading.Timer will check that event after it's done waiting and before it actually executes the callback.实际发生的是cancel方法设置了一个threading.Event ,而实际执行threading.Timer将在完成等待之后和实际执行回调之前检查该事件。

That said, timers are usually implemented without using a separate thread for each one.也就是说,定时器的实现通常不会为每个定时器使用单独的线程。 The best way to do it depends on what your program is actually doing (while waiting for this timer), but anything with an event loop, like GUI and network frameworks, all have ways to request a timer that is hooked into the eventloop.最好的方法取决于你的程序实际在做什么(在等待这个计时器时),但是任何带有事件循环的东西,比如 GUI 和网络框架,都有方法来请求一个挂接到事件循环中的计时器。

Im not sure if best option but for me is woking like this: t = timer_mgr(.....) append to list "timers.append(t)" and then after all created you can call:我不确定是否最好的选择,但对我来说是这样的: t = timer_mgr(.....) append to list "timers.append(t)" 然后在创建之后你可以调用:

for tm in timers:#threading.enumerate():
     print "********", tm.cancel()

my timer_mgr() class is this:我的 timer_mgr() 类是这样的:

class timer_mgr():
def __init__(self, st, t, hFunction, id, name):
    self.is_list = (type(st) is list)
    self.st = st
    self.t = t
    self.id = id
    self.hFunction = hFunction      
    self.thread = threading.Timer(t, self.handle_function, [id])
    self.thread.name = name

def handle_function(self, id):
    if self.is_list:
        print "run_at_time:", datetime.now()
        self.hFunction(id)
        dt = schedule_fixed_times(datetime.now(), self.st)
        print "next:", dt
        self.t = (dt-datetime.now()).total_seconds()
    else:
        self.t = self.st        
        print "run_every", self.t, datetime.now()
        self.hFunction(id)

    self.thread = threading.Timer(self.t, self.handle_function, [id])
    self.thread.start()             

def start(self):
    self.thread.start()

def cancel(self):
    self.thread.cancel()

Inspired by above post.灵感来自上面的帖子。 Cancelable and Resetting Timer in Python. Python 中的可取消和重置计时器。 It uses thread.它使用线程。
Features: Start, Stop, Restart, callback function.功能:启动、停止、重启、回调函数。
Input: Timeout, sleep_chunk values, and callback_function.输入:超时、sleep_chunk 值和 callback_function。
Can use or inherit this class in any other program.可以在任何其他程序中使用或继承此类。 Can also pass arguments to the callback function.也可以将参数传递给回调函数。
Timer should respond in middle also.定时器也应该在中间响应。 Not just after completion of full sleep time.不仅仅是在完成完整的睡眠时间之后。 So instead of using one full sleep, using small chunks of sleep and kept checking event object in loop.因此,与其使用一个完整的睡眠,不如使用一小块睡眠并在循环中不断检查事件对象。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM