【问题标题】:Python timer script doesn't run when set to long periods later稍后设置为长时间时,Python 计时器脚本不会运行
【发布时间】:2012-08-14 09:00:54
【问题描述】:

我想做的是在某个时间执行一个脚本,并且在大多数情况下,当我在执行后的短时间内运行它时,它会起作用,比如大约 10 到 15 分钟。所以我会运行计时器脚本,并在 10 - 15 分钟后执行它的命令。

这是我正在使用的代码:

import time
import myscript
from sys import exit

while 1:
        if time.strftime("%H") == "7" and time.strftime("%M") == "15":
                myscript.main()
                exit()

我想要的是让脚本每天早上执行。当我在当天晚些时候到达我的电脑时,我可以看到脚本卡在这个进程中。

我在两台机器上试过这个,一个 Ubuntu 12.04 64 位机器和一个安装了 cygwin 的 Windows XP 机器,它们都显示了同样的问题。当我离开电脑时,我只是锁定它们,而不是让它们处于待机状态。我尝试运行脚本并锁定它,然后短暂解锁它,但我可以看到这不是问题,因为脚本运行良好。

还要注意,当我使用我的计算机时,它似乎运行得很慢,而且这个脚本似乎占用了大量的 CPU 使用率,在 30 - 50% 的范围内。

我还缺少什么,或者这不是解决问题的理想方法?

【问题讨论】:

  • 在 Unix 系统上,在给定时间运行脚本通常是通过 cron daemon 完成的,更一般地说,busy waiting 不是一个好主意:你至少应该在循环中插入一个延迟,time.sleep(10) .
  • 我最初在脚本执行后有一个睡眠,但我现在将它删除,看看我是否可以让脚本先运行,然后再添加这样的睡眠myscript.main() \ time.sleep(60)
  • 如果你不在那里睡觉,脚本的运行方式会有很大的不同
  • 为什么不:计算到 7:15 之前还有多长时间,然后计算 time.sleep 这段时间? ...或者您是否尝试在 7:15 之前尽可能多地运行此代码?
  • 如果您的机器在 7 点 15 分进入睡眠状态,稍后醒来,您希望发生什么?

标签: python timer strftime


【解决方案1】:

更新:如果您需要在早上 7:15 之后的第一时间运行一次:

now = datetime.now()
dt = now.replace(hour=7, minute=15) #note: ignore seconds, microseconds
if dt < now:
   dt += timedelta(days=1) #note: might miss by an hour on DST transition day
assert dt >= now
delay = (dt - datetime.now()).total_seconds()
Timer(delay, myscript.main).start()

它在早上 7 点 15 分运行main,如果在早上 7 点 15 分处于睡眠状态,则在计算机唤醒后不久运行。


正如其他人所说,现有的解决方案(如 cron)可能更适合在指定时间运行您的脚本。

为避免显式繁忙循环,您可以使用threading.Timer()

#!/usr/bin/env python
from datetime  import datetime, timedelta
from threading import Timer

import myscript

def run_at(dt, func, step=timedelta(days=1), tolerance=timedelta(minutes=1)):
    if abs(dt - datetime.now()) < tolerance:
       func() # don't schedule if it raises an exception

    now = datetime.now()
    while dt < now:
        dt += step

    delay = (dt - datetime.now()).total_seconds()
    Timer(delay, run_at, [dt, func]).start()

dt = datetime.now().replace(hour=7, minute=15)
run_at(dt, myscript.main)

它在当地时间每天7点15分调用main函数。

如果前一个呼叫尚未完成或您的计算机在 7:15 暂停,它会跳过呼叫。它可能会跳过 DST 过渡日。

如果系统时钟在调用之间向后/向前设置,它应该可以工作。

要处理更复杂的调度规范,您可以使用 Python 中的 crontab 语法 example

【讨论】:

    【解决方案2】:

    在那里没有睡眠可以解释为什么您的系统会崩溃。它的旋转速度与您的 CPU 速度一样快。

    如果您只是在试验一个将在特定时间运行函数的包装脚本,您可以这样做:

    from datetime import datetime
    import time
    
    while True:
        now = datetime.now()
        if now.hour == 7 and now.minute == 15:
            foo()
        time.sleep(10)
    

    但这里有一个大问题需要考虑。如果foo() 需要很长时间或挂起自己的操作会怎样?

    您的情况可能是您的睡眠时间(设置为 60 秒)可能真的错过了那个分钟窗口。您必须以较小的增量睡眠,以确保您多次检查分钟。

    除此之外,使用 cron 作业。它旨在执行计划任务。 cron 将存在于您提到的您正在使用的 cygwin shell 中。参考这里setting up a crontab on windows

    【讨论】:

    • 太棒了!但就像我之前提到的,这也适用于 Windows 机器。 Stefano M 说它是最好的 Unix 系统,是吗?
    • 但是你说你在windows上使用的是cygwin。
    • 好的,您必须给我 24 小时的时间才能回复您,以便我看看这是否有效。 :)
    • 这个解决方案对我来说效果最好,因为它很容易实现,而且它也适用于我的 Windows 机器。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2017-05-01
    • 2018-07-02
    • 1970-01-01
    • 2019-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多