【问题标题】:Timer for variable time delay可变时间延迟定时器
【发布时间】:2021-07-01 16:16:00
【问题描述】:

我想要一个计时器(目前使用 Python 3.8),它首先检查系统时间或海军天文台时钟,因此它可以随时启动并与 00 秒同步。

我只对系统时钟或海军天文台的秒数感兴趣。在每分钟的顶部,即秒 = 00 时,我需要将数据写入 DataFrame 或数据库,然后再休眠 60 秒。

我首先检查了系统时间,确定了从 00 秒开始的时间,并为该时间设置了第一个延迟。之后它应该延迟或休眠 60 秒,然后再次运行。数据在不断变化,但此时我只需要每 60 秒写入一次数据,希望它也能够使用其他时间范围,如 5 分钟、15 分钟等,但一旦第一个时间完成,其他时间框架会很容易。

这是我的蹩脚尝试,它运行了几次迭代然后退出,我确信它不是很有效

def time_delay():
    sec = int(time.strftime('%S'))
    if sec != 0:
        wait_time = 60 - sec
        time.sleep(wait_time)
        sec = int(time.strftime('%S'))
        wait_time = 60 - sec
        
    elif time.sleep(60):
        time_delay()    

【问题讨论】:

  • 你所拥有的是无限递归,最终会失败。你可以看看 Python 3 中的 sched 模块。它可以为你处理细节。
  • 你永远不会得到与时钟完全同步的东西,因为在检测到 00(或其他)秒和执行其他东西之间总会有延迟。
  • @TimRoberts:实际上OP的函数不会无限递归,因为time.sleep()总是返回None,这将阻止它调用自己。

标签: python variables time timer delay


【解决方案1】:

这并不像您想要的那样通用,正如我在评论中所说,由于涉及的固有开销,不可能与时间源完全同步(但您可以非常接近)。

下面的作用是定义一个Thread 子类,该子类可用于以固定的时间间隔调用用户指定的函数,从系统时钟的整秒数开始。

它首先延迟到指定秒数的下一个multiple 发生,然后从那时起每隔interval 秒数调用一次函数,同时补偿对指定秒数的调用多长时间函数被执行。

from threading import Thread, Event
import time


class TimedCalls(Thread):
    def __init__(self, func, interval, multiple):
        super().__init__()
        self.func = func
        self.interval = interval
        if multiple == 0:
            self.multiple = 60  # Avoid ZeroDivisionError.
        else:
            self.multiple = multiple
        self.stopped = Event()

    def cancel(self):
        self.stopped.set()

    def start(self):
        # Initially sync to a whole multiple of the interval.
        frac = self.multiple  - (time.time() % self.multiple)
        time.sleep(frac)
        super().start()

    def run(self):
        next_call = time.time()
        while not self.stopped.is_set():
            self.func(next_call)  # Target activity.
            next_call = next_call + self.interval
            # Block until beginning of next interval (unless canceled).
            self.stopped.wait(next_call - time.time())


def my_function(tm):
    print(f"{tm} → {time.strftime('%H:%M:%S', time.localtime(tm))}")


# Call function every 10 sec starting at multiple of 5 secs
timed_calls = TimedCalls(my_function, 10, 5)
timed_calls.start()
try:
    time.sleep(125)  # Let the timed calls occur.
finally:
    timed_calls.cancel()
print('done')

示例输出:

1617662925.0018559 → 15:48:45
1617662935.0018559 → 15:48:55
1617662945.0018559 → 15:49:05
1617662955.0018559 → 15:49:15
1617662965.0018559 → 15:49:25
1617662975.0018559 → 15:49:35
1617662985.0018559 → 15:49:45
1617662995.0018559 → 15:49:55
1617663005.0018559 → 15:50:05
1617663015.0018559 → 15:50:15
1617663025.0018559 → 15:50:25
1617663035.0018559 → 15:50:35
1617663045.0018559 → 15:50:45
done

【讨论】:

  • 非常感谢,我想做的就是你解释得非常好,而且语言通俗易懂。感谢您提供优雅的代码来完成它。也感谢您花时间解释它。如果你教 python,请告诉我如何参加你的课程。
  • Tijoux:不客气。我尝试解释我的答案中的代码是如何工作的(当它不明显时)。有时我什至将 cmets 放入代码中。 ;¬) 在这里表达感谢的最佳方式是投票和/或接受答案。见What should I do when someone answers my question?How does accepting an answer work?
  • P.S.我教 Python 只是因为我试图对 SO 上的合理问题给出很好的答案。
  • 我昨天确实为你的答案投了票,但我的分数太低而无法显示,现在我的分数足够高,我可以投票给你的答案,所以我投了。再次感谢
  • 您赢得了足够的声誉,能够对答案进行投票,因为我对您的 问题 投了赞成票——因为很清楚,展示了一些研究工作,而且您在至少尝试自己解决它。 ;¬) 无论如何,感谢您接受我的回答。
【解决方案2】:

这将在秒为 0 时调用一个函数:

def time_loop(job):
    while True:
        if int(time.time()) % 60 == 0:
            job()
        time.sleep( 1 )

【讨论】:

  • 非常感谢您的解决方案
猜你喜欢
  • 1970-01-01
  • 2011-07-06
  • 1970-01-01
  • 1970-01-01
  • 2013-11-22
  • 2011-03-26
  • 2011-02-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多