每隔x分钟重复运行一次任务

时间:2022-01-09 00:41:26

I am working on a simple Python program, dubbed "Ilmiont DDNS Alerter". As the title may indicate, the aim is to let you know when your dynamic IP address changes.

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

It does this by consulting with an external server. In the Tkinter GUI, the user can select a time frequency to update it on. When they start the updater, I want to schedule the update function to run every x minutes, as specified by the user. I have seen the sched module but it seems to schedule only once. How can I make it check for the new IP repeatedly on the interval until stopped?

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

I am having trouble working out how to schedule this. Additionally, when the updater runs, the GUI goes unresponsive while the process completes. This can take a couple of seconds, especially on slow connections. Presumably threading will overcome this?

我无法解决如何安排这个问题。此外,当更新程序运行时,GUI在进程完成时无响应。这可能需要几秒钟,尤其是在慢速连接上。据推测线程会克服这个?

3 个解决方案

#1


You have really two options:

你有两个选择:

  1. A loop that runs once per 5 (or x) minutes to add to the schedule

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

  2. Or scheduling the function to run again x minutes after it last finished.

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

In either case, your cancel Button would just set a flag somewhere that the running function(s) should check as their first operation.

在任何一种情况下,你的取消按钮都会设置一个标志,运行函数应该检查它作为第一个操作。

The biggest downside with the first case is that it will lock up the execution of your other code. The simpler route is definitely to make the function schedule itself after it runs. If your other code is taking a long time, threading is definitely an option you could investigate; I've not had to use it myself, but something similar to the code below should work:

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

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()

So hit 'Start', and it will print the time every two seconds, plus the other function will run in between. You can hit 'ACTIVE' at any time to prove the interface is responsive. I hope this is helpful? If you're really against the function calling itself, you could probably start a thread that just runs an infinite loop adding events to the queue, but this seems an unnecessary complication.

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

I do note that threading won't be the best choice if the slow_execute function is doing a lot of number crunching, threading is mainly for slow I/O due to the action of the global interpreter lock. Should be fine if you're waiting for results/communications.

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

#2


I think this is similar to what you're looking for, the answer given might work for your issue as well. Loop socket request every 5 seconds (Python)

我认为这与您正在寻找的类似,给出的答案也可能适用于您的问题。每5秒循环套接字请求(Python)

The answer indicates you should you a module of tkinter called "after_idle" that schedules a function the be called once the GUI isn't busy anymore. You can also use .after(time, function) to delay for a specific amount of time before calling the function again.

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

Good luck !

祝好运 !

#3


You can try Threading.Timer

你可以尝试Threading.Timer

See this Example

请参阅此示例

from threading import Timer

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

It will print "Running job_function" every Minute

它会在每分钟打印“Running job_function”

#1


You have really two options:

你有两个选择:

  1. A loop that runs once per 5 (or x) minutes to add to the schedule

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

  2. Or scheduling the function to run again x minutes after it last finished.

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

In either case, your cancel Button would just set a flag somewhere that the running function(s) should check as their first operation.

在任何一种情况下,你的取消按钮都会设置一个标志,运行函数应该检查它作为第一个操作。

The biggest downside with the first case is that it will lock up the execution of your other code. The simpler route is definitely to make the function schedule itself after it runs. If your other code is taking a long time, threading is definitely an option you could investigate; I've not had to use it myself, but something similar to the code below should work:

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

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()

So hit 'Start', and it will print the time every two seconds, plus the other function will run in between. You can hit 'ACTIVE' at any time to prove the interface is responsive. I hope this is helpful? If you're really against the function calling itself, you could probably start a thread that just runs an infinite loop adding events to the queue, but this seems an unnecessary complication.

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

I do note that threading won't be the best choice if the slow_execute function is doing a lot of number crunching, threading is mainly for slow I/O due to the action of the global interpreter lock. Should be fine if you're waiting for results/communications.

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

#2


I think this is similar to what you're looking for, the answer given might work for your issue as well. Loop socket request every 5 seconds (Python)

我认为这与您正在寻找的类似,给出的答案也可能适用于您的问题。每5秒循环套接字请求(Python)

The answer indicates you should you a module of tkinter called "after_idle" that schedules a function the be called once the GUI isn't busy anymore. You can also use .after(time, function) to delay for a specific amount of time before calling the function again.

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

Good luck !

祝好运 !

#3


You can try Threading.Timer

你可以尝试Threading.Timer

See this Example

请参阅此示例

from threading import Timer

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

It will print "Running job_function" every Minute

它会在每分钟打印“Running job_function”