Python sched.scheduler超过了最大递归深度

时间:2009-09-10 10:51:59

标签: python timer clock scheduler

我最近开始学习Python,我正在制作的简单应用程序的一部分包括一个带有hh:mm:ss显示器的计时器,它在自己的线程中运行。

环顾网络,我找到了两种实现方法:

  1. 使用sched.scheduler
  2. 使用threading.Timer
  3. 我这样做的方式对于两种实现看起来都相似:

    附表:

    def tick(self, display, alarm_time):
    
        # Schedule this function to run every minute
        s = sched.scheduler(time.time, time.sleep)
        s.enter(1, 1, self.tick, ([display, alarm_time]))
    
        # Update the time
        self.updateTime(display)
    

    计时器:

    def tick(self, display):
    
        # Schedule this function to run every second
        t = Timer(1, self.tick, (display,alarm_time))
        t.start()
    
        # Update the time
        self.updateTime(display)
    
    1. 关于正确滴答的工作正常,但几分钟后会产生以下错误:RuntimeError:超出最大递归深度。我知道你可以手动增加最大递归级别,但这肯定不是必需的吗?

    2. 没有错误,但偶尔会跳秒,或者不定时滴答。

    3. 有人可以指出我正确的方向如何正确地做到这一点?谢谢。

2 个答案:

答案 0 :(得分:5)

以下是如何将一次性投射到周期性事件中,例如:与sched:如果函数必须创建自己的调度程序并且是在其线程上运行的唯一函数:

def tick(self, display, alarm_time, scheduler=None):
  # make a new scheduler only once & schedule this function immediately
  if scheduler is None:
    scheduler = sched.scheduler(time.time, time.sleep)
    scheduler.enter(0, 1, self.tick, ([display, alarm_time, scheduler]))
    scheduler.run()

  # reschedule this function to run again in a minute
  scheduler.enter(1, 1, self.tick, (display, alarm_time, scheduler]))

  # do whatever actual work this function requires, e.g.:
  self.updateTime(display)

如果还必须在同一个线程中安排其他事件,则必须在其他地方制作和拥有调度程序 - 上面的if部分可以重构为另一种方法,例如:

def scheduleperiodic(self, method, *args):
  self.scheduler = sched.scheduler(time.time, time.sleep)
  self.scheduler.enter(0, 1, method, args)
  # whatever else needs to be scheduled at start, if any, can go here
  self.scheduler.run()

def tick(self, display, alarm_time):
  # reschedule this function to run again in a minute
  self.scheduler.enter(60, 1, self.tick, (display, alarm_time))

  # do whatever actual work this function requires, e.g.:
  self.updateTime(display)

当然,与sched一样,当调度程序正在运行时,它(以及预定的事件回调)将“接管”有问题的线程(所以你需要关闭一个如果你需要在同一时间发生其他事情,请为它分开线程。)

如果你需要在许多函数中使用这种习惯用法,它可以重构为装饰器,但这会掩盖成语的基本简单性,所以我更喜欢这种简单明了的用法。顺便说一句,请注意time.time和time.sleep使用秒,而不是分钟,作为他们的时间单位,所以你需要60而不是一个来表示“从现在起一分钟”; - )。

答案 1 :(得分:4)

计时器是一次性事件。它不能以这种方式循环。

使用Timer调用一个函数,然后创建另一个调用创建Timer的函数的Timer,该函数调用一个创建Timer的函数,...,必须达到递归限制。

您没有提及您的操作系统,但“跳过”或“不规则地滴答”有两个原因。

  1. 您的电脑正忙,“1秒”意味着“非常接近1秒,具体取决于正在发生的事情”

  2. 如果您以0.9999秒启动计时器并等待1秒钟,则可能是1.9999(向下舍入为1)或2.00000。它可能看似复制时间或跳过一段时间。您的计算机的内部硬件时钟非常准确,并且将事物四舍五入到最接近的秒将(始终)导致远程重复或跳过的可能性。

  3. 正确使用sched。 http://docs.python.org/library/sched.html#module-sched

    您的代码段对sched也没有意义。您不需要创建新的调度程序对象。您只需要创建一个新的事件

    在为现有调度程序实例创建新事件时阅读http://docs.python.org/library/sched.html#sched.scheduler.enter