Python 每N秒在后台线程中重复一个函数
我知道这听起来很像,但有不同之处,所以请容忍我 我试图创建一个可重用的“Timer”类,它每N秒调用一次指定的回调,直到调用Python 每N秒在后台线程中重复一个函数,python,python-3.x,python-multithreading,Python,Python 3.x,Python Multithreading,我知道这听起来很像,但有不同之处,所以请容忍我 我试图创建一个可重用的“Timer”类,它每N秒调用一次指定的回调,直到调用stop。作为灵感,我使用了上面的链接,其中包含了一个内置的事件,用stop方法包装。下面是基本类的外观: import time import threading from threading import Thread from threading import Event # Mostly inspired by https://stackoverflow.com/
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()
看起来不错,甚至包括时间。睡眠(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
,但这也不起作用。下面是它的样子:
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的初学者,所以请对您的答案进行充分的解释,以便我能够理解基本问题是什么
我也读了一些关于这个问题的文章,但我不明白这怎么会成为一个问题
作为参考,我正在Ubuntu 17.10上运行Python 3.6.3
不要覆盖start()
。改为覆盖run()
回答很长,因为您需要了解详细信息:
使用第一个代码段中的类定义,您创建了一个从线程
继承的类,但是您已经覆盖了开始()
方法,该方法应该通过一个新方法启动线程,该方法循环直到停止事件
被设置,也就是说,实际启动线程的方法不再这样做了
因此,当您尝试启动线程时,实际上是在当前且唯一的线程中运行调用回调函数的循环。因为它是一个无限循环,所以第二个“线程”没有启动,并且您没有办法“停止”它
您不能覆盖启动
(当然不能以这种方式)。而是重写run
方法。这是启动线程时线程将运行的方法
此外,您应该执行super()。\uuuuu init\uuuuu()
而不是Thread.\uuuu init\uuuuu(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()
.您似乎已经重写了
线程的开始方法,可以想象,这不是一个好主意,特别是如果您从未调用实际的线程。start@pvg这可能是我在Python方面的经验不足。我从链接线程复制粘贴代码,并对其进行修改,使事件成为成员变量而不是外部性。我将在链接问题中做一个注释以编辑代码示例。您没有,我选中了:)。您已经重写了代码,使其无法工作。有人会注意到它在原始答案中不起作用,并指出它。@pvg我确实复制粘贴了它,但在某个时候,我将run
重命名为start
(没有意识到它的含义)。这也许可以解释为什么会有否决票……避免这一切的一个更明智的方法是“不要从线程继承”。线程和计时器之间没有明显的“是”关系。计时器可能是使用线程实现的,它可能包含线程,但它不是线程。@pvg我没有关于它的完整图片。请随意创建一个新答案,并用一些代码解释/说明您的建议。感谢工作代码和详细解释(+1)。我将拭目以待,看看是否有人可以建议如何在不继承线程的情况下执行此操作,如果几天内什么都没有发生,我将接受这个答案。@nightblade9我认为我为您编写代码来回答不同的问题不会有多大收获。你应该接受这个答案——它回答了你的问题,而这个问题本身实际上是一个“打字错误或不再重复”类型的问题,不太可能帮助其他人。您应该做的是按照建议阅读关于线程的文档-它立即涵盖了子类化和委托案例,并明确告诉您不要覆盖除运行
以外的方法。您还可以查看线程教程,例如,它也涵盖了这两种情况。@nightblade9另外,当您熟悉Python时,您可能会对asyncio感兴趣。例如: