Run repeatedly two different functions every n seconds - python

I have two functions: foo() should start every 5 seconds and bar() should start every 10 seconds.
code below:
import threading
import time
def foo():
while True:
time.sleep(5)
print("Call every 5 seconds")
time.sleep(5)
def bar():
while True:
time.sleep(10)
print("Call every 10 seconds")
tr1 = threading.Thread(target=foo)
tr1.start()
tr2 = threading.Thread(target=bar)
tr2.start()
But I think that this is not a good solution.
What is the best way to do this?
And yes, I think that I have memory leak, should I use garbage collector or anything else?
P.S. I hope you could understand what i wrote, because I am not native speaker.

Using the link posted by depperm in the comments
import sched, time
s = sched.scheduler(time.time, time.sleep)
def foo(s):
print("Call every 5 seconds")
s.enter(5, 1, foo, (s,))
def bar(s):
print("Call every 10 seconds")
s.enter(10, 1, bar, (s,))
s.enter(5, 1, foo, (s,))
s.enter(10, 1, bar, (s,))
s.run()

Your code with minor changes, plus some print statements that suggest that this works alright. The 'good' thing about this code is that sleep will raise an exception if the argument to it is negative. Thus, if the codes expected to take less than five or ten seconds respectively take longer then then script will die.
import threading
import time
from datetime import timedelta, datetime
def foo(delay=5):
while True:
t_start = time.time()
print("Call every %s seconds" % delay, datetime.now().strftime('%H.%M.%S'))
t_end = time.time()
time.sleep(delay-(t_end-t_start))
def bar(delay=10):
while True:
t_start = time.time()
print("Call every %s seconds" % delay, datetime.now().strftime('%H.%M.%S'))
t_end = time.time()
time.sleep(delay-(t_end-t_start))
tr1 = threading.Thread(target=foo)
tr1.start()
tr2 = threading.Thread(target=bar)
tr2.start()
Here's the output.
>pythonw -u "temp1.py"
Call every 5 seconds 17.09.51
Call every 10 seconds 17.09.51
Call every 5 seconds 17.09.56
Call every 5 seconds 17.10.01
Call every 10 seconds 17.10.01
Call every 5 seconds 17.10.06
Call every 5 seconds 17.10.11
Call every 10 seconds 17.10.11
Call every 5 seconds 17.10.16
Call every 5 seconds 17.10.21
Call every 10 seconds 17.10.21
Call every 5 seconds 17.10.26
Call every 10 seconds 17.10.31
Call every 5 seconds 17.10.31
Call every 5 seconds 17.10.36
>Process failed to respond; forcing abrupt termination...
>Exit code: 1
I cannot say whether this is the 'best' way of doing this. At least the contents of the functions begin at more or less regular time intervals.

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.

Is there a way to execute code in python for a certain amount of time

For instance for 30 seconds display a 3x3 grid then after the 30 seconds print a new grid. I tried using time.sleep but it does not work. I'm still a beginner in python btw.
Something like what i tried:
print(grid)
time.sleep(30)
print(grid2)
for 30 seconds display...
It sounds a task executing during on time frame, take a look:
import datetime as d
import time
def task():
print "printing grid 3x3..."
#30 seconds from now
END_TIME = d.datetime.now() + d.timedelta(seconds=30)
while d.datetime.now() < END_TIME:
task()
time.sleep(1)
# after 30s
print "after 30s..."
Of course, there's another way:
seconds, count = 30, 0
while count <= seconds:
print count, "- ",
task()
time.sleep(1);
count += 1
print "after 30s..."
However, using datetime you could set script to perform during hours, days or schedule for specific date.

How to make a time sensitive loop in Python?

I want to make a function that prints a statement every 2 minutes. I'm really new to Python and don't fully understand the time library. This is the code I have so far:
from datetime import datetime
import time
now = datetime.now()
print now.second
print "start"
while True:
print "while loop started"
if (now % 2 == 0):
print "Hello"
else:
break
How can I do this?
You can use time.sleep here. Since you want a timer for 2 minutes, pass 120 (seconds) as the argument value.
Basically, this translates into something like below:
while True:
time.sleep(120)
print "Hello"
This will print "Hello" every 2 minutes.
Note that time.sleep is not entirely accurate, and may be off by a small but arbitrary amount of time because of OS scheduling of other processes etc and execution of the code itself.
Use the sched module
import sched, time
s = sched.scheduler(time.time, time.sleep)
def do_something(sc):
print "Doing stuff..."
# do your stuff
sc.enter(60, 1, do_something, (sc,))
s.enter(60, 1, do_something, (s,))
s.run()
take a look here.

Repeat a function for duration

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()

Categories