【问题标题】:Run task repeatedly every x minutes每 x 分钟重复运行一次任务
【发布时间】:2015-05-07 17:15:41
【问题描述】:

我正在开发一个名为“Ilmiont DDNS Alerter”的简单 Python 程序。正如标题所示,目的是让您知道您的动态 IP 地址何时发生变化。

它通过咨询外部服务器来做到这一点。在 Tkinter GUI 中,用户可以选择一个时间频率来更新它。当他们启动更新程序时,我想安排更新功能每 x 分钟运行一次,由用户指定。我见过 sched 模块,但它似乎只安排一次。如何让它在间隔内重复检查新 IP 直到停止?

我无法确定如何安排此活动。此外,当更新程序运行时,GUI 会在进程完成时无响应。这可能需要几秒钟,尤其是在连接速度较慢的情况下。大概线程会克服这个问题?

【问题讨论】:

  • 你能列出并展示你迄今为止尝试过的东西吗?
  • 好吧,我看到另一个人使用了 sched 模块来安排 x 分钟,正如我提到的。然后,在被调用的函数中,他们将新的运行安排为最后一件事,但这似乎相当粗糙,我不确定如何在按钮上取消它。并且它会导致 GUI 无响应问题。
  • 为避免阻塞您的 GUI,您可以使用线程或 createfilrhandler() 异步执行 I/O。见links with code examples in my comments to the related question

标签: python multithreading networking tkinter schedule


【解决方案1】:

我认为这与您正在寻找的类似,给出的答案也可能适用于您的问题。 Loop socket request every 5 seconds (Python)

答案表明您应该使用一个名为“after_idle”的 tkinter 模块来安排一个函数,该函数会在 GUI 不再忙时被调用。您还可以使用 .after(time, function) 在再次调用该函数之前延迟特定的时间。

祝你好运!

【讨论】:

  • 它可以工作,但似乎它只做了一次
  • @Ilmiont:错误。它反复运行。 read_the_socket() 使用 gui.after(5000, read_the_socket) 安排自己。如果请求代码不会长时间阻塞,widget.after() 是更可取的选项。
【解决方案2】:

你有两个选择:

  1. 每 5(或 x)分钟运行一次以添加到计划中的循环

  2. 或安排函数在上次完成后 x 分钟再次运行。

在任何一种情况下,您的cancel 按钮都会在某个地方设置一个标志,正在运行的函数应该将其作为第一次操作进行检查。

第一种情况的最大缺点是它会锁定其他代码的执行。更简单的路线肯定是让函数在运行后自行调度。如果您的其他代码需要很长时间,线程绝对是您可以研究的一个选项;我自己不必使用它,但是类似于下面的代码应该可以工作:

import threading
import tkinter
import time


class RepeatExecute(object):
    def __init__(self,master,t=2000):
        self.master=master
        self.time=t

    def go(self):
        self.GO = True
        self.call_self()

    def call_self(self):
        if self.GO is True:
            t = self.time
            print(time.time())
            thrd = threading.Thread(target=self.slow_execute)
            thrd.start()
            self.master.after(t,self.call_self)

    def set_time(self,t):
        self.time=t

    def stop(self):
        self.GO = False

    def slow_execute(self):
        time.sleep(1.0)
        if self.GO is True:
            print('Halfway')

    def active(self):
        print('Active')


if __name__=='__main__':
    root =tkinter.Tk()
    RE = RepeatExecute(root,t=2000)
    btn1 = tkinter.Button(root,text='Start',command=RE.go)
    btn1.grid()
    btn2 = tkinter.Button(root,text='Stop',command=RE.stop)
    btn2.grid()
    btn3 = tkinter.Button(root,text='ACTIVE!',command=RE.active)
    btn3.grid()
    root.mainloop()

所以点击“开始”,它会每两秒打印一次时间,另外一个函数会在其间运行。您可以随时点击“活动”以证明界面是响应式的。我希望这是有帮助的?如果你真的反对调用自身的函数,你可能会启动一个线程来运行一个无限循环,将事件添加到队列中,但这似乎是不必要的复杂化。

我确实注意到,如果 slow_execute 函数进行大量数字运算,线程不是最佳选择,由于全局解释器锁的作用,线程主要用于慢 I/O。如果您正在等待结果/沟通,应该没问题。

【讨论】:

    【解决方案3】:

    你可以试试Threading.Timer

    看这个例子

    from threading import Timer
    
    def job_function():
        Timer(60, job_function).start ()
        print("Running job_funtion")
    job_function()
    

    它将每分钟打印一次“Running job_function

    【讨论】:

      猜你喜欢
      • 2012-02-05
      • 2014-12-01
      • 2019-11-10
      • 1970-01-01
      • 2016-07-17
      • 2022-07-28
      • 1970-01-01
      • 2014-11-02
      • 2016-03-28
      相关资源
      最近更新 更多