Reputation: 871
What I want is to be able to run a function every second, irrelevant of how long the function takes (it should always be under a second). I've considered a number of options but not sure which is best.
If I just use the delay function it isn't going to take into account the time the function takes to run.
If I time the function and then subtract that from a second and make up the rest in the delay it's not going to take into account the time calculations.
I tried using threading.timer (I'm not sure about the ins and outs of how this works) but it did seem to be slower than the 1s.
Here's the code I tried for testing threading.timer:
def update(i):
sys.stdout.write(str(i)+'\r')
sys.stdout.flush()
print i
i += 1
threading.Timer(1, update, [i]).start()
Is there a way to do this irrelevant of the length of the time the function takes?
Upvotes: 5
Views: 38623
Reputation: 11
If you are working in Jupyter Notebook, you can make use of ipywidgets.Play
widget's observe method to run a function after certain interval without blocking and keeping code in the main thread.
Upvotes: 0
Reputation: 414089
if f()
always takes less than a second then to run it on a one second boundary (without a drift):
import time
while True:
time.sleep(1 - time.monotonic() % 1)
f()
The idea is from @Dave Rove's answer to a similar question.
To understand how it works, consider an example:
time.monotonic()
returns 13.7
and time.sleep(0.3)
is calledf()
is called around (±some error) 14
seconds (since time.monotonic()
epoch)f()
is run and it takes 0.1
(< 1) secondstime.monotonic()
returns around 14.1
seconds and time.sleep(0.9)
is called15
seconds (since time.monotonic()
epoch)f()
is run and it takes 0.3
(< 1) seconds (note: the value is different from Step 2.)time.monotonic()
returns around 15.3
and time.sleep(0.7)
is calledf()
is called around 16
seconds and the loop is repeated.At each step f()
is called on a one second boundary (according to time.monotonic()
timer). The errors do not accumulate. There is no drift.
See also: How to run a function periodically in python (using tkinter).
Upvotes: 6
Reputation: 436
I would like to recommend the following code. You can replace the True with any condition if you want.
while True:
time.sleep(1) #sleep for 1 second
func() #function you want to trigger
Tell me if it works.
Upvotes: -1
Reputation: 32502
The approach using a threading.Timer (see code below) should in fact not be used, as a new thread is launched at every interval and this loop can never be stopped cleanly.
# as seen here: https://stackoverflow.com/a/3393759/1025391
def update(i):
threading.Timer(1, update, [i+1]).start()
# business logic here
If you want a background loop it is better to launch a new thread that runs a loop as described in the other answer. Which is able to receive a stop signal, s.t. you can join()
the thread eventually.
This related answer seems to be a great starting point to implement this.
Upvotes: 7
Reputation: 1530
Threading may be a good choice. The basic concept is as follows.
import threading
def looper():
# i as interval in seconds
threading.Timer(i, looper).start()
# put your action here
foo()
#to start
looper()
Upvotes: 1
Reputation: 1336
This will do it, and its accuracy won't drift with time.
import time
start_time = time.time()
interval = 1
for i in range(20):
time.sleep(start_time + i*interval - time.time())
f()
Upvotes: 10
Reputation: 1342
How about this: After each run, sleep for (1.0 - launch interval)
seconds. You can change the terminate condition by changing while True:
. Although if the your function takes more than 1 second to run, this will go wrong.
from time import time, sleep
while True:
startTime = time()
yourFunction()
endTime = time()-startTime
sleep(1.0-endTime)
Upvotes: 1