每 N 秒在后台线程中重复一个函数
Repeating a function in a background thread every N seconds
我知道这听起来很像 this similarly-worded question,但还是有区别的,所以请耐心等待。
我正在尝试创建一个可重复使用的“计时器”class,它每 N 秒调用一次指定的回调,直到您调用 stop
。作为灵感,我使用了上面的 link,内置事件包装在 stop
方法中。这是基本 class 的样子:
import time
import threading
from threading import Thread
from threading import Event
# Mostly inspired by
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()
看起来不错,甚至包括 time.sleep(0)
基于 this question。
它和我想的不一样;对 start
的调用似乎永远不会 return 或屈服。考虑这个用例:
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)
,但这似乎也没有效果。
我还尝试将其转换为两个 classes:一个只有事件包装器(一个 StoppableTimer
class),另一个只是创建和重新创建 StoppableTimer
在回调中,但这也不起作用。这是它的样子:
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 的内容,但我不明白这怎么可能是个问题。
作为参考,我是 运行 Python 3.6.3 Ubuntu 17.10
简答:
不要覆盖 start()
。改写 run()
。
答案很长,因为您要询问详细信息:
使用第一个代码段中的 class 定义,您创建了一个继承自 Thread
的 class,但是您已经覆盖了假定的 start()
方法通过一个循环直到设置 stop_event
的新方法启动你的线程,也就是说,应该实际启动你的线程的方法不再执行此操作。
因此,当您尝试启动您的线程时,您实际上 运行 循环调用您的回调函数 在您当前且唯一的线程 中。而且由于是无限循环,你的第二个"thread"没有启动,你也没办法"stop"了。
您不能覆盖 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()
我知道这听起来很像 this similarly-worded question,但还是有区别的,所以请耐心等待。
我正在尝试创建一个可重复使用的“计时器”class,它每 N 秒调用一次指定的回调,直到您调用 stop
。作为灵感,我使用了上面的 link,内置事件包装在 stop
方法中。这是基本 class 的样子:
import time
import threading
from threading import Thread
from threading import Event
# Mostly inspired by
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()
看起来不错,甚至包括 time.sleep(0)
基于 this question。
它和我想的不一样;对 start
的调用似乎永远不会 return 或屈服。考虑这个用例:
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)
,但这似乎也没有效果。
我还尝试将其转换为两个 classes:一个只有事件包装器(一个 StoppableTimer
class),另一个只是创建和重新创建 StoppableTimer
在回调中,但这也不起作用。这是它的样子:
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 的内容,但我不明白这怎么可能是个问题。
作为参考,我是 运行 Python 3.6.3 Ubuntu 17.10
简答:
不要覆盖 start()
。改写 run()
。
答案很长,因为您要询问详细信息:
使用第一个代码段中的 class 定义,您创建了一个继承自 Thread
的 class,但是您已经覆盖了假定的 start()
方法通过一个循环直到设置 stop_event
的新方法启动你的线程,也就是说,应该实际启动你的线程的方法不再执行此操作。
因此,当您尝试启动您的线程时,您实际上 运行 循环调用您的回调函数 在您当前且唯一的线程 中。而且由于是无限循环,你的第二个"thread"没有启动,你也没办法"stop"了。
您不能覆盖 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()