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

发布于 2024-08-03 22:23:54 字数 899 浏览 8 评论 0原文

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

环顾网络,我发现了两种实现此方法的方法:

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

我的方法对于两种实现来说看起来都很相似:

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. 在正确计时方面工作正常,但生成以下内容几分钟后出现错误:运行时错误:超出最大递归深度。我知道您可以手动增加最大递归级别,但这里肯定不需要这样做?

  2. 没有错误,但偶尔会跳过秒,或不规则地滴答。

    没有错误

有人可以指出我正确的方向,告诉我如何正确地做到这一点吗?谢谢。

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.

Looking around the web I found two ways of implementing this:

  1. Using sched.scheduler
  2. Using 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. 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不醒的梦 2024-08-10 22:23:54

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

Here's how to make a one-shot into a periodic event, e.g. with sched: if the function must make its own scheduler and be the only thing running on its thread:

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, e.g.:

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).

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";-).

怪异←思 2024-08-10 22:23:54

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

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

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

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

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

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

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

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

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.

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"

  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. 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. http://docs.python.org/library/sched.html#module-sched

Your code snippet makes no sense for sched, either. 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文