Question

I want to execute a function every 60 seconds on Python but I don't want to be blocked meanwhile.

How can I do it asynchronously?

import threading
import time

def f():
    print("hello world")
    threading.Timer(3, f).start()

if __name__ == '__main__':
    f()    
    time.sleep(20)

With this code, the function f is executed every 3 seconds within the 20 seconds time.time. At the end it gives an error and I think that it is because the threading.timer has not been canceled.

How can I cancel it?

Thanks in advance!

Was it helpful?

Solution

You could try the threading.Timer class: http://docs.python.org/library/threading.html#timer-objects.

import threading

def f(f_stop):
    # do something here ...
    if not f_stop.is_set():
        # call f() again in 60 seconds
        threading.Timer(60, f, [f_stop]).start()

f_stop = threading.Event()
# start calling f now and every 60 sec thereafter
f(f_stop)

# stop the thread when needed
#f_stop.set()

OTHER TIPS

It depends on what you actually want to do in the mean time. Threads are the most general and least preferred way of doing it; you should be aware of the issues with threading when you use it: not all (non-Python) code allows access from multiple threads simultaneously, communication between threads should be done using thread-safe datastructures like Queue.Queue, you won't be able to interrupt the thread from outside it, and terminating the program while the thread is still running can lead to a hung interpreter or spurious tracebacks.

Often there's an easier way. If you're doing this in a GUI program, use the GUI library's timer or event functionality. All GUIs have this. Likewise, if you're using another event system, like Twisted or another server-process model, you should be able to hook into the main event loop to cause it to call your function regularly. The non-threading approaches do cause your program to be blocked while the function is pending, but not between functioncalls.

The simplest way is to create a background thread that runs something every 60 seconds. A trivial implementation is:

class BackgroundTimer(Thread):   
   def run(self):
      while 1:
        Time.sleep(60)
        # do something


# ... SNIP ...
# Inside your main thread
# ... SNIP ...

timer = BackgroundTimer()
timer.start()

Obviously, this if the "do something" takes a long time, you'll need to accommodate for it in your sleep statement. But this serves as a good approximation.

I googled around and found the Python circuits Framework, which makes it possible to wait
for a particular event.

The .callEvent(self, event, *channels) method of circuits contains a fire and suspend-until-response functionality, the documentation says:

Fire the given event to the specified channels and suspend execution until it has been dispatched. This method may only be invoked as argument to a yield on the top execution level of a handler (e.g. "yield self.callEvent(event)"). It effectively creates and returns a generator that will be invoked by the main loop until the event has been dispatched (see :func:circuits.core.handlers.handler).

I hope you find it as useful as I do :)
./regards

If you want to invoke the method "on the clock" (e.g. every hour on the hour), you can integrate the following idea with whichever threading mechanism you choose:

import time

def wait(n):
    '''Wait until the next increment of n seconds'''
    x = time.time()
    time.sleep(n-(x%n))
    print time.asctime()

I think the right way to run a thread repeatedly is the next:

import threading
import time

def f():
    print("hello world")  # your code here
    myThread.run()

if __name__ == '__main__':
    myThread = threading.Timer(3, f)  # timer is set to 3 seconds
    myThread.start()
    time.sleep(10)  # it can be loop or other time consuming code here
    if myThread.is_alive():
        myThread.cancel()

With this code, the function f is executed every 3 seconds within the 10 seconds time.sleep(10). At the end running of thread is canceled.

Why dont you create a dedicated thread, in which you put a simple sleeping loop:

#!/usr/bin/env python
import time
while True:
   # Your code here
   time.sleep(60)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top