1

正如您在下面看到的,这是我创建的脚本的副本,有人可以帮助我改进/修复我的currenttime任务。

基本上,白天每隔 3 分钟 +- 60 秒定期调用一次测试,每个周期循环它应该执行以下任务:

  • 在 23:30:00 到 23:40:00 期间的任何地方,它会将 clearscreen 变为 false
  • 在 23:40:00 到 23:50:00 期间的任何地方,它都会检查 clearscreen 是否为假,如果是,则清除某些文件,然后立即将 clearscreen 设置为假
  • 在 23:50:00 到 01:30:00 期间的任何地方,它都会闲置,除了检查时间之外什么都不做。

    from datetime import date, timedelta
    from sched import scheduler
    from time import time, sleep, strftime
    import random
    clearscreen = 0
    
    def periodically(runtime, intsmall, intlarge, function):
        global clearscreen
    
         ## Get current time
        currenttime = strftime('%H:%M:%S')
    
        ## while currenttime is anywhere between 23:40 and 23:50 then...
        while currenttime > '23:30:00' and currenttime < '23:40:00':
            ## Update time
            currenttime = strftime('%H:%M:%S')
            print ("""23:30:00 to 23:40:00 | %s""" % (currenttime))
            sleep(1)
    
            ## If clearscreen = false then...
            if clearscreen == False:
                ## Set clearscreen to true to enable the next part work and to disable this part until the next day.
                clearscreen = True
                print "changed to true"
    
        ## If currenttime is anywhere between 23:50 and 23:59 then...
        while currenttime > '23:40:00' and currenttime < '23:50:00':
            ## Update time
            currenttime = strftime('%H:%M:%S')
            print ("""23:40:00 to 23:50:00 | %s""" % (currenttime))
            sleep(1)
    
            if clearscreen == True:
                ## clear stuff here
                print "cleared"
                ## Change clearscreen to to stop it running
                clearscreen = False
                print "changed to false"
    
        ## Only allow run_periodically during 01:30 and 23:30
        if clearscreen == False:
            while currenttime > '23:50:00' and currenttime < '23:59:59':
                ## Update time
                currenttime = strftime('%H:%M:%S')
                print ("""23:50:00 to 23:59:59 | %s""" % (currenttime))
                sleep(1)
            while currenttime > '00:00:00' and currenttime < '01:30:00':
                ## Update time
                currenttime = strftime('%H:%M:%S')
                print ("""00:00:00 to 01:30:00 | %s""" % (currenttime))
                sleep(1)
    
        runtime += random.randrange(intsmall, intlarge)
        s.enter(runtime, 1, function, ())
        s.run()
    
    def test():
        print "test function"
    
    while True:
        periodically(180, -60, +60, test)
    

任何帮助将非常感激。

编辑@abarnert

关于循环,这是函数应该做的事情:

23:3x:xx - While loop initiated as currenttime fits the while loop's conditions (time is inbetween 23:30:00 and 23:40:00)
23:3x:xx - clearscreen is false, setting it to true.
23:3x:xx to 23:40:00 - currenttime is updated every 1 second(s)
23:40:01 - While loop ended as currenttime no longer fits the while loop's conditions (time is outside of 23:30:00 and 23:40:00)

23:40:01 - While loop initiated as currenttime fits the while loop's conditions (time is inbetween 23:40:00 and 23:50:00)
23:40:01 - clearscreen is true, doing some stuff and then changing clearscreen to false
23:40:01 to 23:50:00 - currenttime is updated every 1 second(s)
23:50:01 - While loop ended as currenttime no longer fits the while loop's conditions (time is outside of 23:40:00 and 23:50:00)

23:50:01 - While loop initiated as currenttime fits the while loop's conditions (time is inbetween 23:50:00 and 23:59:59)
23:50:01 to 23:59:59 - currenttime is updated every 1 second(s)
00:00:00 - While loop ended as currenttime no longer fits the while loop's conditions (time is outside of 23:50:00 and 23:59:59)

00:00:00 - While loop initiated as currenttime fits the while loop's conditions (time is inbetween 00:00:00 and 01:30:00)
00:00:00 and 01:30:00 - currenttime is updated every 1 second(s)
00:00:00 - While loop ended as currenttime no longer fits the while loop's conditions (time is outside of 00:00:00 and 01:30:00)

你提到我反复更新当前时间,然后打印,然后睡觉。我将如何解决这个“问题”?


关于global clearscreen我不确定你的意思;“你没有锁”


我正在运行 Windows,所以 signal.setitemer 是不行的,而且我需要将某些值/变量存储在我的脚本的内存中,所以 Windows 上的计划任务不合适吗?

您使用该模块构建了一个示例代码,sched但它不起作用,我无法弄清楚如何让它工作,而且它对我来说也相当混乱。我还在学习,这很混乱。

4

1 回答 1

3

Python 不可能“忽略 while 循环”(除非您在它们之外还有其他条件)。但是如果 while 循环告诉 Python 循环 0 次,它就会这样做。


首先,你有这个循环:

while currenttime > '23:30:00' and currenttime < '23:40:00':

……接下来是这个:

while currenttime > '23:40:00' and currenttime < '23:50:00':

想想 23:40:00 会发生什么。它既不是在 23:40:00 之前也不是在 23:40:00 之后,因此您甚至会在进入第二个循环之前跳过它。

当我们在这里时,这些行有两个旁注:

  • 你可以只用'23:40:00' < currenttime < '23:50:00'Python 编写。
  • 您可以使用datetimeortime对象而不是字符串来比较时间。

接下来,您反复执行此操作:

currenttime = strftime('%H:%M:%S')
print ("""23:40:00 to 23:50:00 | %s""" % (currenttime))
sleep(1)

这意味着这currenttime实际上永远不是当前时间。通常是一秒钟前。想想这对边缘的循环条件有什么影响。

作为旁注,sleep(1)不能保证恰好睡一秒钟。如果您的计算机很忙,或者决定进入低功耗模式,它的运行时间可能会明显超过一秒。如果中断正在飞行,它可能会短于一秒。即使在最好的情况下,它通常也会在一个方向或另一个方向上偏移半个时钟滴答。所以,如果你需要它精确地触发 600 次,它通常不会那样做。


同时,你有这个:

global clearscreen

显然,任何人都无法在您当前的代码中更改它,因此大概在您的真实代码中,您正试图从另一个线程更改它。但是你没有锁定它。因此,您完全有可能不会立即看到更改,甚至永远不会看到更改。


编写调度程序比看起来要难得多。这就是为什么你通常最好使用现有的。选项包括:

  • 标准库sched模块。
  • 标准库threading.Timer
  • 标准库signal.setitemer。仅在具有真实信号的平台上(不是 Windows),如果您使用线程或fork.
  • PyPI 上的各种第三方模块/ActiveState 上的食谱可以为您提供更好的Timer(例如,使用单个计时器线程和即将到来的作业队列,而不是每个作业的线程)。
  • 一个处理定时器的事件循环框架——尽管如果你只需要调度,这可能是多余的,如果你有其他理由使用 Twisted 或 wx 或 PyGame 或 gevent,让它来做调度。
  • 运行脚本的外部计时器——任何 Unix 上的 cron、Mac 和其他一些 Unix 上的 LaunchServices、Windows 上的计划任务等。可能不适合每秒运行一个任务,但从你的评论来看,听起来你真正需要的是“能够每 3 分钟 +- 60 秒调用一次函数。”

既然你特别问sched...有两种方法:

  1. 一次建立一整天的日程表,并enterabs反复调用以填充当天的任务,再加上一个明天午夜运行并执行相同操作的任务。
  2. 编写一个函数,根据当前时间计算出接下来要安排哪个任务以及何时安排,然后执行此操作。在实际工作之后调用该函数。

这是第一个的样子:

import sched
import datetime
import time

s = sched.scheduler(time.time, time.sleep)

def dotoday():
    now = datetime.date.now()
    stime = now.time()

    # Schedule "first" every 3 minutes from 22:00 to 22:57
    if stime < datetime.time(22, 0):
        stime = datetime.time(22, 0)
    while stime <= datetime.time(22, 57):
        s.enterabs(stime, 1, first, ())
        stime += datetime.timedelta(0, 180)

    # Schedule "second" every 3 minutes from 23:00 to 23:57
    stime = datetime.time(23, 0)
    while stime <= datetime.time(23, 57):
        s.enterabs(stime, 1, second, ())
        stime += datetime.timedelta(0, 180)

    # Schedule "dotoday" to run tomorrow
    midnight = now.replace(hour=0, minute=0, second=0)
    tomorrow = midnight + datetime.timedelta(1, 0)
    s.enterabs(tomorrow, 1, dotoday, ())

dotoday()
s.run()

我把它弄得比必要的复杂一点,这样你就可以在 23:31:17 启动它,它会在 23:31:17、23:34:17 等运行第一批任务,而不是等到23:33:00、23:36:00 等

于 2013-07-10T18:37:18.340 回答