【问题标题】:Python sched.scheduler exceeds max recursion depthPython sched.scheduler 超过最大递归深度
【发布时间】:2009-09-10 10:51:59
【问题描述】:

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

环顾网络,我发现了两种实现方式:

  1. 使用 sched.scheduler
  2. 使用 threading.Timer

这两种实现的方式看起来很相似:

预定:

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. 没有错误,但有时会跳过秒数,或不规则滴答。

有人可以为我指出正确的方向吗?谢谢。

【问题讨论】:

  • 请张贴您找到的使用 threading.Timer 的链接。
  • 您的问题标题完全错误。您的 Timer 超出了递归深度。不是 sched.scheduler。
  • 对不起,如果我不清楚。已编辑的问题。使用 Timer 的建议来自这里 docs.python.org/library/sched.html> 请记住,我只是一个初学者,可能有错误的想法。

标签: python timer clock scheduler


【解决方案1】:

以下是如何将一次性事件变成周期性事件,例如with 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 来表示“从现在开始一分钟”;-)。

【讨论】:

  • 我保留了装饰师的建议
【解决方案2】:

计时器是一次性事件。不能这样循环。

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

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

  1. 您的计算机正忙,“1 秒”表示“接近 1 秒,具体取决于其他情况”

  2. 如果您在 0.9999 秒处启动计时器并等待 1 秒,您可能会处于 1.9999(向下舍入为 1)或 2.00000。它可能会出现重复时间或跳过时间。您计算机的内部硬件时钟非常准确,四舍五入到最接近的秒将(总是)导致重复或跳过的远程可能性。

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

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

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

【讨论】:

  • 感谢您的回答。我已经澄清了这个问题,包括我的 sched 实现和错误,但我猜原因与你为 Timer 给出的原因相同。但是,如果 sched 只是在以后安排一个事件,我仍然看不到如何避免递归限制:(
  • 除了指向python文档页面的链接之外,那么“正确的方向”是什么:)
  • 调用 threading.Timer() 是递归吗?还是调用Timer后函数返回?
  • 不,不是。这个答案开始完全错误。我刚刚写了一个小脚本,它什么都不做,只是使用 Timer 和零延迟创建了一个无限的“递归”,现在它已经运行了几分钟。
猜你喜欢
  • 2016-07-09
  • 2011-12-31
  • 1970-01-01
  • 1970-01-01
  • 2011-02-12
  • 2022-08-07
  • 2020-07-13
  • 2021-02-07
  • 2017-03-18
相关资源
最近更新 更多