Repeat a function for duration - python

In python 3 how can you repeat a function for say 10 seconds. In this case the function is turning outputs on a raspberry pi high and low for specific amounts of time. This needs to happen for an amount of time specified prior to this happening.

Try:
def run_wrapper(sec):
starttime = datetime.datetime.now()
endtime = None
while True:
f()
endtime = datetime.datetime.now()
if (endtime - starttime).total_seconds() >= sec:
break
print('Ran for %s seconds' % (endtime - starttime).total_seconds())
where f is the function you want to call. Keep in mind that this doesn't run for exactly sec seconds. It calls the function if sec seconds haven't passed. For example if your function takes, say 30 seconds, and you specify 31 seconds, your function will be called twice for a total of 60 seconds.

If you don't need the function to be continuously re-called throughout the duration of the time, then you could just do this:
import time
f()
time.sleep(sec)
g()
Here f is a function that causes some result that is undone by g; since g isn't called until after sec seconds have passed, the results of f will stay in effect for as long as you need.
Edit: if f takes a non-trivial amount of time and you need this to be more precise, try the following:
import time
before_f = time.clock()
f()
after_f = time.clock()
time.sleep(sec-(after_f-before_f))
g()

Related

Is there a way to execute a python script with consistent execution time by time padding if necessary?

I know the execution time for any python program shall depend on the OS and cannot be controlled by the User. But what I want is the program to go in sleep if the execution time is lower than necessary.
Let's say I have a python program which has a print statement at the end.
def foo():
...
...
return(ans)
print(foo())
Using timeit I have evaluated the range of execution time taken for foo. Let it be from 0.8 seconds to 5.5 seconds. I choose the execution time of the complete script as 10 seconds to be on the safe side.
I want the program to add delay of 9.2 seconds before print statement if the execution of foo was completed in 0.8 seconds. Likewise a delay of 4.5 seconds if execution was completed in 5.5 seconds.
You basically just have to sleep for the amount of time that is the difference between the maximum time and actual execution time. you could also make a general purpose decorator.
class padtime:
def __init__(self, maxtime):
self.maxtime = float(maxtime)
def __call__(self, f):
def _f(*args, **kwargs):
start = time.time()
ret = f(*args, **kwargs)
end = time.time()
delay = self.maxtime - (end - start)
if delay > 0.0:
time.sleep(delay)
return ret
return _f
#padtime(9.5)
def foo():
...
return("Answer")
that could be applied to any function.
You can measure the execution time of foo() using two calls to time.time(). You can then compute the amount of time to stall the execution of the program using the computed execution time of foo():
import time
def foo():
...
start_time = time.time()
foo()
end_time = time.time()
if end_time - start_time < 10:
time.sleep(10 - (end_time - start_time))
Note that we use time.sleep() rather than a while loop that repeatedly checks whether enough time has elapsed, since busy waiting wastes resources.

Ensure that an arbitrary code takes 15 minutes to run

I need code that will do this:
def foo():
now = datetime.datetime.utcnow()
# Some code will run that takes a variable amount of time
# (less than 15 minutes)
# This code should run no sooner than 15 minutes after `now`
Note that this is not the same as using time.sleep! time.sleep would halt the entire process, but I need computation in foo() to happen and for foo() to return no sooner than 15 minutes after it begins.
You need to calculate the time between the current time and the desired restart time. Then sleep for that amount of time.
wait_time = 15 # minutes
restart_time = datetime.datetime.now() + datetime.timedelta(minutes=wait_time)
# execute code that takes a long time
# for example, let's just sleep for some time
random_time = random.randint(1, wait_time)
time.sleep(random_time * 60)
print("See you again at ", restart_time)
# Now, calculate how long you need to sleep to resume at restart_time
sleep_time = restart_time - datetime.datetime.now()
# Sleep for that amount of time
time.sleep(sleep_time.total_seconds())
print("Hi, I'm back ", datetime.datetime.now())
datetime is not needed, because we do not need to think in human clock terms (hours, minutes, seconds).
All we need is a number of seconds since any fixed moment in the past and time.monotonic does exactly that.
import time
DELAY = 900 # in seconds
start = time.monotonic()
# computation here
end = time.monotonic()
duration = end - start
time.sleep(DELAY - duration)
Last three lines can be written as time.sleep(start + DELAY - time.monotonic()), I split it for simplicity.
import time
import random
import datetime
wait = random.randint(1, 14)
now = datetime.datetime.utcnow()
print(now)
time.sleep(wait * 60)
now = datetime.datetime.utcnow()
print(now)
I think this solves it.

A cycle that ends as soon as x seconds have passed

I'm trying to make a program with a cycle that ends as soon as sixty seconds have passed but I don't have the slightest idea of how to do so, any ideas?
You can use the time module to get the system time before the execution of the loop, and then make the loop condition so that it stops when 60 seconds have passed.
import time
seconds = 60
start_time = time.time()
while (time.time() - start_time) < seconds:
print("hello !")

Make a timer using sleep in python. How to account for computation time?

I'm trying to make a simple timer which prints the time remaining every second.
for k in range(100):
print(100-k)
t.sleep(1)
#output
#100
#99
#98
#...
#1
However, this will take slightly longer than 100 seconds, because there will be a delay added when print() is used. For long periods, this is slightly noticeable. Is there a way to account for this, and accurately display the time every second? I know I could just sleep(100), but this wouldn't let the time left be printed.
import time
start_time=time.time()
for k in range(25):
print(25-k)
time.sleep(1)
print("it took "+str(float(time.time()-start_time)*1000)+" Milliseconds")
the output with print is: it took 26412.75382041931 Milliseconds
the output without print : it took 25053.035020828247 Milliseconds
it should have been just 25000 milliseconds but it is not
printing will take time, even reading the code takes time
point is don't expect accurate timing with time.sleep() !!!
You can use time.time() to measure elapsed time.
import time
start_time = time.time()
for k in range(100):
# k seconds SHOULD be elapsed at this point
print(100 - k)
slept_time = time.time() - start_time
time.sleep(1 + k-slept_time)
Using time.sleep will never give you the accurate time for your timer, since the time it takes is the one second sleep time + printing time, you can use threading.Timer to get more accurate results. https://repl.it/Hwkt :
import threading, time
start_time=time.time()
def count_loop(counter):
if counter <= 0:
print("it took "+str(float(time.time()-start_time)*1000)+" Milliseconds")
return
threading.Timer(1.0, count_loop, args=[counter-1]).start()
print(counter)
count_loop(100)
This is still not accurate, but with only very minimum offset, only 45 ms. However, when using time.sleep from legendisback's example, there is apparently 81 ms delay. https://repl.it/HwlK

With python: intervals at x:00 repeat

How do I sched a repeat timer for 5 min intervals. Which fire at 00 seconds, then repeat at 00. Ok, not hard real-time but as close as possible with sys lags. Trying to avoid a build up in lags and get near 00.
Lang: Python, OS: WinXP x64
System has 25ms resolution.
Any code would be helpful, tia
I don't know how to do it any more accurately than with threading.Timer. It's "one-shot", but that just means the function you schedule that way must immediately re-schedule itself for another 300 seconds later, first thing. (You can add accuracy by measuring the exact time with time.time each time and varying the next scheduling delay accordingly).
Try and compare the time printouts of these two code samples:
Code Sample 1
import time
delay = 5
while True:
now = time.time()
print time.strftime("%H:%M:%S", time.localtime(now))
# As you will observe, this will take about 2 seconds,
# making the loop iterate every 5 + 2 seconds or so.
## repeat 5000 times
for i in range(5000):
sum(range(10000))
# This will sleep for 5 more seconds
time.sleep(delay)
Code Sample 2
import time
delay = 5
while True:
now = time.time()
print time.strftime("%H:%M:%S", time.localtime(now))
# As you will observe, this will take about 2 seconds,
# but the loop will iterate every 5 seconds because code
# execution time was accounted for.
## repeat 5000 times
for i in range(5000):
sum(range(10000))
# This will sleep for as long as it takes to get to the
# next 5-second mark
time.sleep(delay - (time.time() - now))

Categories