What is the best way to repeatedly execute a function every x seconds?

后端 未结 18 2681
不知归路
不知归路 2020-11-21 06:04

I want to repeatedly execute a function in Python every 60 seconds forever (just like an NSTimer in Objective C). This code will run as a daemon and is effectively like call

相关标签:
18条回答
  • 2020-11-21 06:29

    Here's an update to the code from MestreLion that avoids drifiting over time.

    The RepeatedTimer class here calls the given function every "interval" seconds as requested by the OP; the schedule doesn't depend on how long the function takes to execute. I like this solution since it doesn't have external library dependencies; this is just pure python.

    import threading 
    import time
    
    class RepeatedTimer(object):
      def __init__(self, interval, function, *args, **kwargs):
        self._timer = None
        self.interval = interval
        self.function = function
        self.args = args
        self.kwargs = kwargs
        self.is_running = False
        self.next_call = time.time()
        self.start()
    
      def _run(self):
        self.is_running = False
        self.start()
        self.function(*self.args, **self.kwargs)
    
      def start(self):
        if not self.is_running:
          self.next_call += self.interval
          self._timer = threading.Timer(self.next_call - time.time(), self._run)
          self._timer.start()
          self.is_running = True
    
      def stop(self):
        self._timer.cancel()
        self.is_running = False
    

    Sample usage (copied from MestreLion's answer):

    from time import sleep
    
    def hello(name):
        print "Hello %s!" % name
    
    print "starting..."
    rt = RepeatedTimer(1, hello, "World") # it auto-starts, no need of rt.start()
    try:
        sleep(5) # your long-running job goes here...
    finally:
        rt.stop() # better in a try/finally block to make sure the program ends!
    
    0 讨论(0)
  • 2020-11-21 06:29

    The main difference between that and cron is that an exception will kill the daemon for good. You might want to wrap with an exception catcher and logger.

    0 讨论(0)
  • 2020-11-21 06:31

    The easier way I believe to be:

    import time
    
    def executeSomething():
        #code here
        time.sleep(60)
    
    while True:
        executeSomething()
    

    This way your code is executed, then it waits 60 seconds then it executes again, waits, execute, etc... No need to complicate things :D

    0 讨论(0)
  • 2020-11-21 06:34
    import time, traceback
    
    def every(delay, task):
      next_time = time.time() + delay
      while True:
        time.sleep(max(0, next_time - time.time()))
        try:
          task()
        except Exception:
          traceback.print_exc()
          # in production code you might want to have this instead of course:
          # logger.exception("Problem while executing repetitive task.")
        # skip tasks if we are behind schedule:
        next_time += (time.time() - next_time) // delay * delay + delay
    
    def foo():
      print("foo", time.time())
    
    every(5, foo)
    

    If you want to do this without blocking your remaining code, you can use this to let it run in its own thread:

    import threading
    threading.Thread(target=lambda: every(5, foo)).start()
    

    This solution combines several features rarely found combined in the other solutions:

    • Exception handling: As far as possible on this level, exceptions are handled properly, i. e. get logged for debugging purposes without aborting our program.
    • No chaining: The common chain-like implementation (for scheduling the next event) you find in many answers is brittle in the aspect that if anything goes wrong within the scheduling mechanism (threading.Timer or whatever), this will terminate the chain. No further executions will happen then, even if the reason of the problem is already fixed. A simple loop and waiting with a simple sleep() is much more robust in comparison.
    • No drift: My solution keeps an exact track of the times it is supposed to run at. There is no drift depending on the execution time (as in many other solutions).
    • Skipping: My solution will skip tasks if one execution took too much time (e. g. do X every five seconds, but X took 6 seconds). This is the standard cron behavior (and for a good reason). Many other solutions then simply execute the task several times in a row without any delay. For most cases (e. g. cleanup tasks) this is not wished. If it is wished, simply use next_time += delay instead.
    0 讨论(0)
  • 2020-11-21 06:34

    One possible answer:

    import time
    t=time.time()
    
    while True:
        if time.time()-t>10:
            #run your task here
            t=time.time()
    
    0 讨论(0)
  • 2020-11-21 06:34
        ''' tracking number of times it prints'''
    import threading
    
    global timeInterval
    count=0
    def printit():
      threading.Timer(timeInterval, printit).start()
      print( "Hello, World!")
      global count
      count=count+1
      print(count)
    printit
    
    if __name__ == "__main__":
        timeInterval= int(input('Enter Time in Seconds:'))
        printit()
    
    0 讨论(0)
提交回复
热议问题