【问题标题】:Python: Run code every n seconds and restart timer on conditionPython:每n秒运行一次代码并在条件下重新启动计时器
【发布时间】:2023-03-06 11:33:01
【问题描述】:

这可能比我想象的要简单,但我想创建一个计时器,当达到限制(比如 15 分钟)时,会执行一些代码。

与此同时,我想测试一个条件。如果满足条件,则重置计时器并重新开始该过程,否则继续倒计时。

如果在倒计时结束后满足条件,则执行一些代码,计时器再次开始倒计时。

这是否涉及threading 还是可以通过简单的time.sleep() 函数来实现?

【问题讨论】:

  • 条件是如何设置的?它是在您的脚本中异步设置的,还是您定期检查一些外部条件?
  • 注意:从 15 分钟开始可能会出现明显的偏差,因为 time.slee() 被调用了 100 次——到目前为止所有答案 (except mine) 都引入了 "drift"

标签: python timer counter


【解决方案1】:

您可以通过线程非常优雅地完成它,但如果您需要快速修复,您可以尝试

import time
timer = 15 * 60 # 60 seconds times 15 mins
while timer > 0:
    time.sleep(0.985) # don't sleep for a full second or else you'll be off
    timer -= 1
    if someCondition:
          timer = 15 * 60
executeCode() # called when time is zero and while loop is exited

【讨论】:

    【解决方案2】:

    如果整个过程像你说的那么简单,我会这样(半伪代码):

    def run_every_fifteen_minutes():
      pass
    def should_reset_timer():
      pass
    def main():
      timer = 0
      while True:
        time.sleep(1)
        timer+=1
        if should_reset_timer():
          timer = 0
        if timer == 15*60:
          run_every_fifteen_minutes()
          timer = 0
    

    请注意,这不会正好是十五分钟。可能会晚几秒钟。睡眠不能保证只睡 1 秒,循环的其余部分也需要一些时间。如果您需要它非常准确,您可以在其中添加系统时间比较。

    【讨论】:

      【解决方案3】:

      感谢大家的帮助,您的回答为我指明了正确的方向。最后我想出了:

      #!/usr/bin/python
      import RPi.GPIO as GPIO
      import time
      import subprocess
      
      GPIO.setmode(GPIO.BCM)
      PIR_PIN = 4
      GPIO.setup(PIR_PIN, GPIO.IN)
      timer = 15 * 60 # 60 seconds times 15 mins
      
      subprocess.call("sudo /opt/vc/bin/tvservice -o", shell=True)
      
      try :
          print "Screen Timer (CTRL+C to exit)"
          time.sleep(5)
          print "Ready..."
      
          while True:
              time.sleep(0.985)
      
              # Test PIR_PIN condition
              current_state = GPIO.input(PIR_PIN)
      
              if timer > 0:
                  timer -= 1
      
                  if current_state: #is true
                      # Reset timer
                      timer = 15 * 60
      
              else:
                  if current_state: #is true
                      subprocess.call("sudo /opt/vc/bin/tvservice -p", shell=True)
      
                      # Reset timer
                      timer = 15 * 60
                  else:
                      subprocess.call("sudo /opt/vc/bin/tvservice -o", shell=True)
      
      except KeyboardInterrupt:
          print "Quit"
          GPIO.cleanup()
      

      具体来说,我使用 PIR 传感器来检测运动并在 Raspberry Pi 上打开连接 hdmi 的显示器。在 15 分钟没有移动后,我想关闭显示器,然后如果(稍后)检测到移动,再次打开它并重新开始计时。

      【讨论】:

        【解决方案4】:

        描述听起来类似于dead main's switch / watchdog timer。它的实现方式取决于您的应用程序:是否有事件循环、是否有阻塞函数、是否需要单独的进程进行适当隔离等。如果代码中没有函数阻塞:

        #!/usr/bin/env python3
        import time
        from time import time as timer
        
        timeout = 900 # 15 minutes in seconds
        countdown = timeout # reset the count
        while True:
            time.sleep(1 - timer() % 1) # lock with the timer, to avoid drift
            countdown -= 1
            if should_reset_count():
                countdown = timeout # reset the count
            if countdown <= 0: # timeout happened
                countdown = timeout # reset the count
                "some code is executed"
        

        代码假定睡眠永远不会被中断(注意:在 Python 3.5 之前,睡眠可能会被信号中断)。该代码还假设没有函数花费大量(大约一秒钟)时间。否则,您应该使用明确的截止日期(相同的代码结构):

        deadline = timer() + timeout # reset
        while True:
            time.sleep(1 - timer() % 1) # lock with the timer, to avoid drift
            if should_reset_count():
                deadline = timer() + timeout # reset
            if deadline < timer(): # timeout
                deadline = timer() + timeout # reset
                "some code is executed"
        

        【讨论】:

          【解决方案5】:

          也许您应该研究一下 Linux 工具 cron 来安排脚本的执行。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-03-24
            • 2022-12-11
            • 1970-01-01
            • 2020-07-15
            • 2013-02-23
            • 2018-12-19
            • 2014-04-24
            • 1970-01-01
            相关资源
            最近更新 更多