按需触发的周期性Python线程

1 投票
1 回答
2553 浏览
提问于 2025-04-17 08:29

我有一个简单的PyGTK应用程序。因为我需要定期执行多个任务来获取一些数据并刷新界面,所以我像这样扩展了线程:

class MyThread(threading.Thread):        
    def __init__(self):
        threading.Thread.__init__(self)
        self.setDaemon(True)
        self.event = threading.Event()
        self.event.set()

    def run(self):
        while self.event.is_set():
            timer = threading.Timer(60, self._run)   
            timer.start()
            timer.join()

    def cancel(self):
        self.event.clear()

    def _run(self):
        gtk.threads_enter()
        # do what need to be done, fetch data, update GUI
        gtk.threads_leave()

我在应用程序启动时启动这些线程,把它们保存在一个列表里,并在退出前取消它们。这样做效果很好。

但现在我想添加一个刷新按钮,这样可以强制其中一个线程立即运行,而不是等到设定的时间再运行(如果它当前没有在运行的话)。

我尝试通过在MyThread中添加一个布尔变量来表示线程是否正在运行(在_run之前设置为真,完成时重置为假),然后如果没有在运行就直接调用MyThread._run(),但这样导致我的应用程序变得无响应,_run任务也永远无法完成。

我不太明白为什么会这样。解决这个问题的最佳方法是什么?如果我能让刷新在后台运行,这样就不会阻塞界面,那也很好。

也许可以调用run,并把秒数设置为1,这样计时器就能更快触发它?

1 个回答

4

与其使用一个 Timer,不如用另一个 Event 对象配合超时来实现。这样你就可以在按钮的回调函数里设置这个事件。下面的代码演示了这个方法(我把你的取消代码删掉了,以便让它更简洁):

import threading

class MyThread(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)
        self.sleep_event = threading.Event()
        self.damon = True

    def run(self):
        while True:
            self.sleep_event.clear()
            self.sleep_event.wait(60)
            threading.Thread(target=self._run).start()

    def _run(self):
        print "run"

my_thread = MyThread()
my_thread.start()

while True:
    raw_input("Hit ENTER to force execution\n")
    my_thread.sleep_event.set()

默认情况下,“run”会每60秒打印一次。如果你按下ENTER键,它会立即打印一次,然后再过60秒打印一次,依此类推。

撰写回答