I have two functions, function1 and function2. I want to execute function1 for only 5 seconds, and then execute function2 for only 3 seconds and then repeat it.
I tried time.sleep() function, but it freezes entire program not executing any function.
I tried asyncio and threading, but it just executing both functions at same time.
def function1():
//do something
def funtion2():
//do something else
while True:
function1()
// execute function1 for 5 seconds
function2()
// execute function2 for 3 seconds
How precise do you need to be? Are you needing to account for the runtime of the functions themselves? That will be quite difficult.
Here's a simple approach:
import time # built-in module
def timed_execution(func, s, *args, **kwargs):
t0 = time.time()
while True:
func(*args, **kwargs)
if time.time() - t0 >= s:
break
timed_execution(function1, 5)
timed_execution(function2, 3)
If you'd like to get a little more fancy, and the times your functions need to execute is always the same, you could use a decorator:
import time
def timer(s):
def timed_func(func):
def timed_execution(*args, **kwargs):
t0 = time.time()
while True:
func(*args, **kwargs)
if time.time() - t0 >= s:
break
return timed_execution
return timed_func
#timer(5)
def function1():
pass
#timer(3)
def function2():
pass
If you want to use a decorator with a parameter for the amount of time, but only optionally, you'll need to do a bit more work. See how to do a conditional decorator.
Related
I have a question about adding delay after calling various functions.
Let's say I've function like:
def my_func1():
print("Function 1")
def my_func2():
print("Function 2")
def my_func3():
print("Function 3")
Currently I've added delay between invoking them like below:
delay = 1
my_func1()
time.sleep(delay)
my_func2()
time.sleep(delay)
my_func3()
time.sleep(delay)
As you can see I needed a few times time.sleep, which I would like to avoid.
Using decorator is also not an option, since it might be that I would like to avoid delay when calling one of this function not in a group.
Do you have any tip how to beautify this?
You can define something like this:
def delay_it(delay, fn, *args, **kwargs):
return_value = fn(*args, **kwargs)
time.sleep(delay)
then
a = delay_it(1, my_func1, "arg1", arg2="arg2")
b = delay_it(1, my_func2, "arg3")
...
I've tested this based on "How to Make Decorators Optionally Turn On Or Off" (How to Make Decorators Optionally Turn On Or Off)
from time import sleep
def funcdelay(func):
def inner():
func()
print('inner')
sleep(1)
inner.nodelay = func
return inner
#funcdelay
def my_func1():
print("Function 1")
#funcdelay
def my_func2():
print("Function 2")
#funcdelay
def my_func3():
print("Function 3")
my_func1()
my_func2()
my_func3()
my_func1.nodelay()
my_func2.nodelay()
my_func3.nodelay()
Output:
Function 1
inner
Function 2
inner
Function 3
inner
Function 1
Function 2
Function 3
You can see that it can bypass the delay.
Not sure if I know what you mean but you could try:
functions = [my_func1, my_func2, my_func3]
for func in functions:
func()
time.sleep(1)
It's not a good way to handle delay in a function; because each function should do only one thing.
Dont't do this:
def my_func(delay):
# do stuff
if delay>0:
time.sleep(delay)
Try to make a delay handler function and put suitable delay after each function you pass to it.
Try this:
def delay_handler(functions_list,inputs_list,delay_list):
for function,cur_input,delay in zip(functions_list,inputs_list,delay_list):
function(*cur_input)
time.sleep(delay)
Tip 1: Zip will iterate throw each list (any iterable) simultaneously; first elements in inputs_list and delay_list are for first function in function_list and etc.
Tip 2: The '*' behind a list will unpack it.
I want to create a function that calculates the execution time of other functions, but when I do that, I get an error like: 'int' object is not callable. What is the problem here?
import time
def square(x):
return x**2
def timer(func):
t1 = time.perf_counter()
func()
t2 = time.perf_counter()
print(t2-t1)
timer(square(5))
It is also possible to modify your code to make it work, but you'll have to pass in the arguments of square() into timer() after passing in the function as the first argument:
def timer(func, *args, **kwargs):
t1 = time.perf_counter()
func(*args, **kwargs)
t2 = time.perf_counter()
print(t2-t1)
timer(square, 5)
Using *args* and **kwargs lets us deal with functions with arbitrary parameters.
A more convenient way to do this is to use a decorator. It returns a wrapper function around the original function. You don't have to change much in order to time a particular function. Here's an example:
def timer(func):
def wrapper(*args, **kwargs):
func_name = func.__name__
print(f"Starting {func_name}")
t1 = time.perf_counter()
output = func(*args, **kwargs)
t2 = time.perf_counter()
print(f"Total time for {func_name}: {t2 - t1:.3f} s\n")
return output
return wrapper
To use it, simply do:
#timer
def square(x):
return x**2
square(5)
Or:
def square(x):
return x**2
timed_square = timer(square)
timed_square(5)
Your timer expects a function to call, but you're giving it the result of already calling one (and that result isn't a function).
You can do timer(lambda: square(5)) instead. Then it's your timer function that executes the (anonymous) function and thus the expression square(5) as intended.
square(5) return 25; so you're trying to run your timer on a number ;)
Try instead:
import time
def timer(func):
def f(args):
t1 = time.perf_counter()
ret = func(args)
t2 = time.perf_counter()
print('execution time: {}'.format(t2-t1))
return ret
return f
def square(x):
return x**2
timedSqure = timer(square)
res = timedSqure(5)
print(res)
Further, I recommend on learning decorators in python, because with decorators you can make it even more elegant by declaring:
#timer
def square(x):
return x**2
See repl here
And last, per #Heap Overflow's comment: it doesn't make sense to time something that runs so quickly. If you want to benchmark a function you should use timeit
If I have a function called a lot of times in a for loop and this function sometimes is running too much time, how can I use a timer for each call of function(to set and reset the timer each time)?
It looks like:
def theFunction(*args):
#some code (timer is on)
#In this point time is out, break and exit function
#Timer is reseted
for i in range(0,100):
theFunction(*args)
Use the time module like so:
import time
time_start = time.time()
#Do function stuff
time_stop = time.time()
#Check your time now
timed_segment = time_stop - time_start
#Repeat if needed
To run this multiple times in a for loop you will need to append times into a list as it runs like so:
import time
def function():
times_list = []
for x in range(10)
time_start = time.time()
#Do function stuff
time_stop = time.time()
#Check your time now
timed_segment = time_stop - time_start
times_list.append(timed_segment)
#Repeat as many times as needed
return times_list
If you want to break after a certain amount of time you can use a while loop instead like so:
import time
def function():
times_list = []
time_start = time.time()
time_end = time.time()
while time_end - time_start < 10: #after 10 seconds the while loop will time out
#Your function does stuff here
time_end = time.time()
#Next, append times to a list if needed
time_list.append(time_start - time_end)
return times_list
To stop the function after a certain time regardless of where it is, we can use threading like so:
import threading
from time import sleep
def do_stuff():
sleep(10)
print("1 + 2")
return
t = threading.Thread(target=do_stuff)
t.start()
t.join(timeout = 5)
In the above example, calling timeout in join will kill the thread after 5 seconds. We can also put this into a decorator if we plan on reusing it many times like so:
import threading
from time import sleep
def timeout(func):
def inner_func(*nums, **kwargs):
t = threading.Thread(target=func, args=(*nums,))
t.start()
t.join(timeout=5)
return inner_func
#timeout
def do_stuff(a,b):
sleep(3)
print(a+b)
return
do_stuff(1,3)
There is another module called timeit which can measure the execution time of small code snippets. I believe you can use that also. I have never used that module but it should work.
Here is the link to the doc page. Give it a look :: https://docs.python.org/2/library/timeit.html
see How to use timeit module as well
For high re-usability and ease of implementations, I would recommend -
Using decorators -
from time import time
def time_it(func):
def wrapper(*args, **kwargs):
a=time()
func(*args, **kwargs)
print(a-time())
return wrapper
#time_it
def foo(s='this works'):
print(s)
foo()
Using profile.run - https://docs.python.org/2/library/profile.html#module-profile
I'm building a wrapper for an API which demands at least 1 second of waiting between each call. I thought I could solve this using a decorator in the following way:
import datetime, time
last_time = datetime.datetime(2014, 1, 1)
def interval_assurer(f):
global last_time
if (datetime.datetime.now() - last_time).seconds < 1:
print("Too fast...")
time.sleep(1)
last_time = datetime.datetime.now()
return f
#interval_assurer
def post():
pass
This won't work though, for some reason, and I'm not sure why. last_time gets updated the first time the post is called, but won't update afterwards. Please keep in mind that this is the first time I'm experimenting with decorators, so I am probably missing something fundamental.
Thanks.
Since your interval_assurer is a decorator, it's called exactly once: when the function is defined, and not when it's called. You need to create a wrapping function like this:
import time, functools
def interval_assurer(f):
last_time = [0]
#functools.wraps(f) # optional, but nice to have
def wrapper(*args, **kwargs):
time_diff = time.time() - last_time[0]
if time_diff < 1:
print("Too fast...")
time.sleep(1 - time_diff)
last_time[0] = time.time()
return f(*args, **kwargs)
return wrapper
#interval_assurer
def post(self, **kwargs):
pass
You also won't need the global then (the trick with the list can be replaced with nonlocal in Python 3).
The decorator function just returns the original function, so the timing code only runs when the decorator is called, i.e. when the function definition is evaluated. Instead, it should return a new function that incorporates the timing code and calls f when appropriate.
Try something like:
def interval_assurer(f):
def func():
global last_time
if (datetime.datetime.now() - last_time).seconds < 1:
print("Too fast...")
time.sleep(1)
last_time = datetime.datetime.now()
return f()
return func
If your decorated function takes arguments, you should include *args, **kwargs in the definition of func and the call to f; also, consider decorating func in turn with functools.wraps(f).
Building on #bereal's answer, you can make the last_time an attribute of the wrapper function to remove the global (allowing multiple wrapped functions, each with their own timer), and even make a decorator that takes an argument for the interval to enforce:
import functools
import time
def interval_assured(interval):
"""Ensure consecutive calls are separated by a minimal interval."""
def wrapper(f):
#functools.wraps(f)
def func(*args, **kwargs):
if (time.time() - func.last_time) < interval:
time.sleep(interval)
result = f(*args, **kwargs)
func.last_time = time.time()
return result
func.last_time = time.time()
return func
return wrapper
Note that the time is reset after the wrapped function f is called - this is important if the run-time of f is large relative to the interval.
In use:
>>> def testing(x):
print time.time()
print x
>>> for x in range(3):
testing(x)
1405938405.97
0
1405938406.01
1
1405938406.02
2
>>> #interval_assured(5)
def testing(x):
print time.time()
print x
>>> for x in range(3):
testing(x)
1405938429.71
0
1405938434.73
1
1405938439.75
2
I have recently posted a question about how to postpone execution of a function in Python (kind of equivalent to Javascript setTimeout) and it turns out to be a simple task using threading.Timer (well, simple as long as the function does not share state with other code, but that would create problems in any event-driven environment).
Now I am trying to do better and emulate setInterval. For those who are not familiar with Javascript, setInterval allows to repeat a call to a function every x seconds, without blocking the execution of other code. I have created this example decorator:
import time, threading
def setInterval(interval, times = -1):
# This will be the actual decorator,
# with fixed interval and times parameter
def outer_wrap(function):
# This will be the function to be
# called
def wrap(*args, **kwargs):
# This is another function to be executed
# in a different thread to simulate setInterval
def inner_wrap():
i = 0
while i != times:
time.sleep(interval)
function(*args, **kwargs)
i += 1
threading.Timer(0, inner_wrap).start()
return wrap
return outer_wrap
to be used as follows
#setInterval(1, 3)
def foo(a):
print(a)
foo('bar')
# Will print 'bar' 3 times with 1 second delays
and it seems to me it is working fine. My problem is that
it seems overly complicated, and I fear I may have missed a simpler/better mechanism
the decorator can be called without the second parameter, in which case it will go on forever. When I say foreover, I mean forever - even calling sys.exit() from the main thread will not stop it, nor will hitting Ctrl+c. The only way to stop it is to kill python process from the outside. I would like to be able to send a signal from the main thread that would stop the callback. But I am a beginner with threads - how can I communicate between them?
EDIT In case anyone wonders, this is the final version of the decorator, thanks to the help of jd
import threading
def setInterval(interval, times = -1):
# This will be the actual decorator,
# with fixed interval and times parameter
def outer_wrap(function):
# This will be the function to be
# called
def wrap(*args, **kwargs):
stop = threading.Event()
# This is another function to be executed
# in a different thread to simulate setInterval
def inner_wrap():
i = 0
while i != times and not stop.isSet():
stop.wait(interval)
function(*args, **kwargs)
i += 1
t = threading.Timer(0, inner_wrap)
t.daemon = True
t.start()
return stop
return wrap
return outer_wrap
It can be used with a fixed amount of repetitions as above
#setInterval(1, 3)
def foo(a):
print(a)
foo('bar')
# Will print 'bar' 3 times with 1 second delays
or can be left to run until it receives a stop signal
import time
#setInterval(1)
def foo(a):
print(a)
stopper = foo('bar')
time.sleep(5)
stopper.set()
# It will stop here, after printing 'bar' 5 times.
Your solution looks fine to me.
There are several ways to communicate with threads. To order a thread to stop, you can use threading.Event(), which has a wait() method that you can use instead of time.sleep().
stop_event = threading.Event()
...
stop_event.wait(1.)
if stop_event.isSet():
return
...
For your thread to exit when the program is terminated, set its daemon attribute to True before calling start(). This applies to Timer() objects as well because they subclass threading.Thread. See http://docs.python.org/library/threading.html#threading.Thread.daemon
Maybe these are the easiest setInterval equivalent in python:
import threading
def set_interval(func, sec):
def func_wrapper():
set_interval(func, sec)
func()
t = threading.Timer(sec, func_wrapper)
t.start()
return t
Maybe a bit simpler is to use recursive calls to Timer:
from threading import Timer
import atexit
class Repeat(object):
count = 0
#staticmethod
def repeat(rep, delay, func):
"repeat func rep times with a delay given in seconds"
if Repeat.count < rep:
# call func, you might want to add args here
func()
Repeat.count += 1
# setup a timer which calls repeat recursively
# again, if you need args for func, you have to add them here
timer = Timer(delay, Repeat.repeat, (rep, delay, func))
# register timer.cancel to stop the timer when you exit the interpreter
atexit.register(timer.cancel)
timer.start()
def foo():
print "bar"
Repeat.repeat(3,2,foo)
atexit allows to signal stopping with CTRL-C.
this class Interval
class ali:
def __init__(self):
self.sure = True;
def aliv(self,func,san):
print "ali naber";
self.setInterVal(func, san);
def setInterVal(self,func, san):
# istenilen saniye veya dakika aralığında program calışır.
def func_Calistir():
func(func,san); #calışıcak fonksiyon.
self.t = threading.Timer(san, func_Calistir)
self.t.start()
return self.t
a = ali();
a.setInterVal(a.aliv,5);