简体   繁体   English

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

[英]Python sched.scheduler exceeds max recursion depth

I have recently started learning Python and part of the simple app I am making includes a timer with a hh:mm:ss display running in its own thread. 我最近开始学习Python,我正在制作的简单应用程序的一部分包括一个带有hh:mm:ss显示器的计时器,它在自己的线程中运行。

Looking around the web I found two ways of implementing this: 环顾网络,我找到了两种实现方法:

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

The way I did it looks similar for both implementations: 我这样做的方式对于两种实现看起来都相似:

sched: 附表:

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)

Timer: 计时器:

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. Works fine with regards to ticking correctly, but generates the following error after a few minutes: RuntimeError: maximum recursion depth exceeded. 关于正确滴答的工作正常,但几分钟后会产生以下错误:RuntimeError:超出最大递归深度。 I know you can increase the max recursion level manually, but surely this should not be necessary here? 我知道你可以手动增加最大递归级别,但这肯定不是必需的吗?

  2. No error, but occasionally the seconds will skip, or tick irregularly. 没有错误,但偶尔会跳秒,或者不规则地滴答。

Can someone please point me in the right direction as to how to do this correctly? 有人可以指出我正确的方向如何正确地做到这一点? Thank you. 谢谢。

Here's how to make a one-shot into a periodic event, eg with sched : if the function must make its own scheduler and be the only thing running on its thread: 以下是如何将一次性事件转换为周期性事件,例如使用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 other events must also be scheduled in the same thread then the scheduler must be made and owned "elsewhere" -- the if part above can get refactored into another method, eg: 如果还必须在同一个线程中安排其他事件,则必须在其他地方制作和拥有调度程序 - 上面的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)

Again, of course and as always with sched , while the scheduler is running, it (and the scheduled event callbacks) will "take over" the thread in question (so you'll need to hive off a separate thread for it if you need other things to be happening at the same time). 同样,当然并且一如既往地使用sched ,当调度程序运行时,它(以及预定的事件回调)将“接管”有问题的线程(因此,如果需要,您将需要为其创建一个单独的线程其他事情要同时发生)。

If you need to use this kind of idiom in many functions it could be refactored into a decorator, but that would somewhat mask the underlying simplicity of the idiom, so I prefer this simple, overt use. 如果你需要在许多函数中使用这种习惯用法,它可以被重构为装饰器,但这有点掩盖了成语的基本简单性,所以我更喜欢这种简单明了的用法。 BTW, note that time.time and time.sleep use seconds, not minutes, as their unit of time, so you need 60, not one, to indicate "a minute from now";-). 顺便说一句,请注意time.time和time.sleep使用秒,而不是分钟作为他们的时间单位,所以你需要60而不是一个来表示“从现在起一分钟”;-)。

A Timer is a one-shot event. 定时器是一次性事件。 It cannot be made to loop this way. 它不能以这种方式循环。

Using a Timer to call a function which then creates another Timer which calls a function that creates a Timer which calls a function which creates a Timer, ..., must reach the recursion limit. 使用Timer调用一个函数,然后创建另一个调用创建Timer的函数的Timer,该函数调用一个创建Timer的函数,...,必须达到递归限制。

You don't mention your OS, but the "skipping" or "ticking irregularly" is for two reasons. 你没有提到你的操作系统,但“跳过”或“不规则地滴答”有两个原因。

  1. You computer is busy and "1 second" means "pretty close to 1 second, depending on what else is going on" 你的电脑很忙,“1秒钟”意味着“非常接近1秒,取决于其他的情况”

  2. If you start your timer at 0.9999 seconds, and wait 1 second, you might be at 1.9999 (rounds down to 1) or 2.00000. 如果您以0.9999秒启动计时器并等待1秒钟,则可能是1.9999(向下舍入为1)或2.00000。 It may appear to duplicate a time or skip a time. 它可能看似复制时间或跳过一段时间。 Your computer's internal hardware clock is very accurate, and rounding things off to the nearest second will (always) lead to the remote possibility of duplicates or skips. 您的计算机的内部硬件时钟非常准确,并且将事物四舍五入到最接近的秒将(始终)导致远程重复或跳过的可能性。

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

Your code snippet makes no sense for sched, either. 你的代码片段对sched也没有意义。 You do not need to create a new scheduler object. 您不需要创建新的调度程序对象。 You only need to create a new event . 您只需要创建一个新事件

Read http://docs.python.org/library/sched.html#sched.scheduler.enter on creating a new event for an existing scheduler instance. 阅读http://docs.python.org/library/sched.html#sched.scheduler.enter ,了解如何为现有调度程序实例创建新事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM