我知道这听起来很像this similarly-worded question,但也有差异,所以请耐心等待。
我试图创建一个可重复使用的"计时器"每隔N秒调用指定回调的类,直到您调用stop
。作为灵感,我使用上面的链接,内置事件包裹在stop
方法中。以下是基础课的外观:
import time
import threading
from threading import Thread
from threading import Event
# Mostly inspired by https://stackoverflow.com/questions/12435211/python-threading-timer-repeat-function-every-n-seconds
class RepeatingTimer(Thread):
def __init__(self, interval_seconds, callback):
Thread.__init__(self)
self.stop_event = Event()
self.interval_seconds = interval_seconds
self.callback = callback
self.setDaemon(True)
def start(self):
while not self.stop_event.wait(self.interval_seconds):
self.callback()
time.sleep(0) # doesn't seem to do anything
def stop(self):
self.stop_event.set()
看起来不错,甚至包括基于this question的time.sleep(0)
。
它没有做我的想法;对start
的呼唤似乎永远不会回归或屈服。考虑一下这个用例:
def print_status(message):
print(message)
def print_r1():
print_status("R1")
def print_r2():
print_status("R2")
r1 = RepeatingTimer(1, print_r1)
r2 = RepeatingTimer(0.5, print_r2)
r1.start()
r2.start()
对r1.start
的调用永远不会终止。它会永远持续下去。四秒钟后,控制台上的输出为:
R1
R1
R1
R1
这促使我介绍了time.sleep(0)
电话,虽然这似乎没有做任何事情。
我也尝试过使用和不使用self.setDaemon(True)
,但这似乎也没有效果。
我也尝试将它转换为两个类:一个只有事件包装器(一个StoppableTimer
类),另一个只是在回调中创建并重新创建StoppableTimer
,但是没有#39} ;或者工作。这是它的样子:
class StoppableTimer(Thread):
def __init__(self, interval_seconds, callback):
Thread.__init__(self)
self.stop_event = Event()
self.interval_seconds = interval_seconds
self.callback = callback
self.setDaemon(True)
def start(self):
time.sleep(self.interval_seconds)
self.callback()
def stop(self):
self.stop_event.set()
class RepeatingTimer:
def __init__(self, interval_seconds, callback):
self.interval_seconds = interval_seconds
self.callback = callback
self.timer = StoppableTimer(interval_seconds, self.refresh_timer)
def start(self):
self.timer.start()
def stop(self):
self.timer.stop()
def refresh_timer(self):
self.stop()
self.callback()
self.timer = StoppableTimer(self.interval_seconds, self.refresh_timer)
self.timer.start()
我完全不知道如何做这项工作。我也主要是Python的初学者,所以请为你的答案添加足够的解释,以便我掌握基本问题。
我还读了一些Global Interpreter Lock on SO,但我不明白这可能是一个问题。
作为参考,我在Ubuntu 17.10上运行Python 3.6.3
答案 0 :(得分:3)
简短回答:
不要覆盖start()
。改为覆盖run()
。
答案很长,因为您要求提供详细信息:
通过第一个代码段中的类定义,您创建了一个继承自Thread
的类,但是您已经覆盖了start()
方法,该方法应该通过在设置stop_event
之前循环的新方法,也就是说,实际启动你的线程的方法不再这样做了。
因此,当您尝试启动线程时,实际上是在当前且唯一的线程中运行调用回调函数的循环。因为它是一个无限循环,你的第二个"线程"没有开始,你没有办法停止"停止"它
你不能覆盖start
(不是这样)。相反,覆盖run
方法。这是您启动它时将由您的线程运行的方法。
此外,您应该super().__init__()
而不是Thread.__init__(self)
。第一个是在Python中调用继承方法的正确方法。
class RepeatingTimer(Thread):
def __init__(self, interval_seconds, callback):
super().__init__()
self.stop_event = Event()
self.interval_seconds = interval_seconds
self.callback = callback
def run(self):
while not self.stop_event.wait(self.interval_seconds):
self.callback()
def stop(self):
self.stop_event.set()
使用您已定义的功能,您可以执行以下操作:
r1 = RepeatingTimer(1, print_r1)
r2 = RepeatingTimer(0.5, print_r2)
r1.start()
r2.start()
time.sleep(4)
r1.stop()
r2.stop()