gpt4 book ai didi

python - 每 N 秒在后台线程中重复执行一个函数

转载 作者:行者123 更新时间:2023-11-30 22:26:13 27 4
gpt4 key购买 nike

我知道这听起来很像this similarly-worded question ,但还是有差异的,所以请耐心等待。

我正在尝试创建一个可重用的“Timer”类,该类每 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 questiontime.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 ,但这也行不通。它看起来像这样:

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

最佳答案

简短回答:

不要重写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()

Here is the relevant documentation for Thread .

关于python - 每 N 秒在后台线程中重复执行一个函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47291633/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com