如何循环一个函数以每 15 分钟(在 0/15/30/45 分钟标记处)执行一次任务?

How to loop a function to perform a task every 15 minutes (on the 0/15/30/45 minute mark)?

我在 Raspberry Pi 上有一个程序 运行,我想每 15 分钟在每小时的 0、15、30 和 45 分钟从温度计中提取一些数据。

我已经使用 while 循环尝试过,我以前有效地使用了 time.sleep(900),但有时会偏离整点后的 0、15、30 和 45 分钟。

目前我有这个;

from datetime import datetime

def run(condition):
    while condition == True:
        if (datetime.now().minute == (0 or 15 or 30 or 45)):
            #perform some task
        temperature_store()

为了简单起见,我没有深入了解 temperature_store() 的作用,但它从插入 Pi 的传感器读取温度,然后打印出来。

我希望 temperature_store() 每 15 分钟发生一次,但目前它每秒发生一次。

我知道这可能是因为我 while 循环的 logic/syntax 错误,但我无法弄清楚。 (对 python 脚本和时间延迟没有太多经验)。

有两种方法可以做到这一点:'easy' 方式和稳定方式。

简单的方法就是执行以下操作:

from datetime import datetime
from time import sleep

def run(condition):
    while datetime.now().minute not in {0, 15, 30, 45}:  # Wait 1 second until we are synced up with the 'every 15 minutes' clock
        sleep(1)

    def task():
        # Your task goes here
        # Functionised because we need to call it twice
        temperature_store()
    
    task()

    while condition == True:
        sleep(60*15)  # Wait for 15 minutes
        task()

这实际上是在等待我们与正确的分钟同步,然后执行它,并在循环之前等待 15 分钟。如果您愿意,可以使用它,这是最简单的方法 in pure Python。然而,这方面的问题数不胜数:

  • 它与分钟同步,而不是秒
  • 它取决于机器,在某些机器上可能会给出不正确的读数
  • 需要持续运行!

第二种方法是按照评论中的建议使用cron-jobs。这是优越的,因为:

  • 它使用系统级事件,而不是计时器,因此我们可以确保尽可能准确
  • 因为我们没有等待,所以没有错误的余地
  • 一旦它得到上述事件setter,它只会运行调用函数setter。

因此,简单地使用(假设您使用 Linux):

from crontab import CronTab

cron = CronTab(user='username')  # Initialise a new CronTab instance
job = cron.new(command='python yourfile.py')  # create a new task
job.minute.on(0, 15, 30, 45)  # Define that it should be on every 0th, 15th, 30th and 45th minute

cron.write()  # 'Start' the task (i.e trigger the cron-job, but through the Python library instead

(显然,适当配置 username

yourfile.py 中,在同一路径中,只需将 temperature_store() 的代码放入即可。

希望对您有所帮助。显然,如果您愿意,可以使用第一种方法,甚至可以使用评论中的建议,但我只是觉得整个循环结构有点太脆弱了,尤其是在 Raspberry Pi 上。如果您想将其他物联网设备连接到您的 Pi,这应该更稳定和可扩展。

我针对每 15 秒打印秒数的程序进行了模块测试。
下面的代码不包含 sleep().
您可以在下面的代码中将 second 更改为 minute 以每 15 分钟执行一次任务。

from datetime import datetime

while True:
    a = datetime.now().second
    if (a % 15) == 0:  # every 15 seconds
        print(a)  # ---- To do something every 15 seconds ---- #
        while True:  # discard any milliseconds or duplicated 15 seconds
            a = datetime.now().second
            if (a % 15) is not 0:
                break

但我认为 cron 或任何其他调度程序模块都是不错的选择。

我想出了以下答案,使用了@geza-kerecsenyi 的答案中的一些逻辑

def run():
    first = True
    while first == True:
        second = True
        while second == True:
            if datetime.now().minute == 0 or datetime.now().minute ==15 or datetime.now().minute ==30 or datetime.now().minute == 45:
                action()
                sleep(899)

我不确定哪一个在 CPU 方面更好,或者哪个在 运行 方面更有效,但两者的逻辑似乎都很合理。

[@geza-kerecsenyi 会将您的答案标记为正确]