I have a function wrapper for my test cases that keeps track of how much time the function takes, then outputs some basic info using print. The code for my function wrapper is below:
TEST_INIT_START = datetime.datetime.now()
def timedisplay(func):
#functools.wraps(func)
def wrapper(self, *args, **kwargs):
start = datetime.datetime.now()
try:
return func(self, *args, **kwargs)
finally:
print()
print(
'Total time elapsed:',
(datetime.datetime.now() - TEST_INIT_START).seconds,
'seconds',
)
print(
f'{func.__name__} test time elapsed:',
(datetime.datetime.now() - start).seconds,
'seconds',
)
print('Result: ', end='')
return wrapper
The expected output for a test case using this wrapper would be something like:
test_some_function (tests.test_some_function) ...
Total time elapsed: 2 seconds
test_some_function test time elapsed: 2 seconds
Result: ok
But the weird thing is this is what I'm actually getting:
test_some_function (tests.test_some_function) ... Result:
Total time elapsed: 2 seconds
test_some_function test time elapsed: 2 seconds
ok
For some reason the output is getting written to the console with the final print statement first. My first thought would be that the calls to datetime.datetime.now() are releasing the GIL and executing the most simple statement before it's required, but I don't have any information to back that up. My question is mainly why this would be happening, and how to get it to execute properly.
Related
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.
I have the following celery chain process:
#app.task(name='bcakground')
def background_task():
now = datetime.now()
ids = [700,701,708,722,783,799]
for id in ids:
my_process = chain(taks1.s(id), task2.s())
my_process()
end = datetime.now()
return ['ENDED IN',(end-now).total_seconds()]
Q1: How can I tell how long it takes for this task to complete from beginning to end? The result I get to (ENDED IN) doesnt reflect the truth because the chain is run in parallel and the results are a fraction of second.
Q2 is there any way to place a termination timeout in the event the entire process of background_task takes longer then 25 minutes?
I think you can use wraps from functools there is an answers to a similar question here: timeit-versus-timing-decorator. #jonaprieto gives an example of using wraps in the link, I have reproduced below. This should allow you to achieve what you want.
from functools import wraps
from time import time
def timing(f):
#wraps(f)
def wrap(*args, **kw):
ts = time()
result = f(*args, **kw)
te = time()
print 'func:%r args:[%r, %r] took: %2.4f sec' % \
(f.__name__, args, kw, te-ts)
return result
return wrap
in an example:
#timing
def f(a):
for _ in range(a):
i = 0
return -1
Invoking method f wrapped with #timing:
func:'f' args:[(100000000,), {}] took: 14.2240 sec
f(100000000)
For this, I use timedelta, it returns the difference between two datetime arguments.
import datetime
start_at = datetime.datetime.now()
# do your thing!
end = datetime.timedelta(seconds=(datetime.datetime.now() - start_at).total_seconds())
With this code, when you print(end) it will return a result like 0:00:00.253998
Trying to add executing Process(Test,a,b) Name in the decoration where i am calculating Elapsed Time.Need Suggestions.
Final Expected Logs:
Process **a** elapsed time :3.8 || Rowcount=1833
Process **test** elapsed time :7.8 || Rowcount=1133
code
import time
from queries import a,b,test
def elapsedTimeTracker_decorator(func):
def wrapper():
start_time = time.time()
func()
print(test)
end_time = time.time()
elapsed_time = end_time - start_time
print('elapsed_time:'+ str(elapsed_time) +'||' + 'RowCount:' + str(cursor.rowcount))
return wrapper
print "Process a started"
elapsedTimeTracker_decorator(lambda: cursor.execute(a))()
print "Process Test started"
elapsedTimeTracker_decorator(lambda: cursor.execute(Test))()
print "Process b started"
elapsedTimeTracker_decorator(lambda: cursor.execute(b))()
a,b & test Consists of SQL Update Queries
test = """INSERT INTO users
select * from user_all where user_id=54549172 """
If you wish to print extra data for a decorated lambda that takes no arguments, then you have to pass it to your decorator:
def elapsedTimeTracker_decorator(func, test):
def wrapper():
start_time = time.time()
func()
print(f'Process {test} elapsed time: {time.time() - start_time} || Rowcount={cursor.rowcount}')
return wrapper
elapsedTimeTracker_decorator(lambda: cursor.execute(test), test)()
Other than that I have no idea where your test is supposed to comes from. Please elaborate with more details if that is not a suitable solution.
EDIT: Based on the latest information provided, it is clear that you do not need to use a lambda, nor a decorator with an inner wrapper. You could simply use a simple function that call the given one with the provided arguments and keywords that would take care of the call along with printing the execution time. For example:
from time import time as now
def time_call(func, *args, **kwargs):
cur = now()
func(*args, **kwargs)
print(
f'Executing {func.__qualname__}({repr(args)[1:-1]}, ' +
f'{"".join(f"{k}={v}" for k, v in kwargs.items())}) took ' +
f'{now() - cur} seconds.'
)
def test(foo, bar, baz):
pass
time_call(test, 'foo', 'bar', baz=None)
Which would prints something like:
Executing test('foo', 'bar', baz=None) took 0.0 seconds.
I have a python code snippet that allows me to time function as a decorator. I would like to add function name to the output. and time in milli-seconds
def func_timer(func):
def f(*args, **kwargs):
start = time.time()
results = func(*args, **kwargs)
print "Elapsed: %.6fs" % (time.time() - start)
return results
return f
Usage is:
#func_timer
def foo():
pass
Current Output is :
Elapsed: 0.005168s
Output desired:
foo Elapsed: 5.168ms
Function objects have a __name__ attribute, you can use that. Simply multiply the time by 1000 if you want milliseconds:
print "%s Elapsed: %.6fms" % (func.__name__, (time.time() - start) * 1000)
I want to make my function run for a particular period like for 5 seconds; how I can do that ?
Like,
def my_function():
while(time == 10 seconds):
......... #run this for 10 seconds
def my_next_function():
while(time == 5 seconds):
......... #run this for 5 seconds
This will definitely help you.
import time
def myfunc():
now=time.time()
timer = 0
while timer != 10:
end = time.time()
timer = round(end-now)
def mynextfunc():
now=time.time()
timer = 0
while timer != 5:
end = time.time()
timer = round(end-now)
myfunc()
print "myfunc() exited after 10 seconds"
mynextfunc()
print "mynextfunc() exited after 5 seconds"
I'd use a <=, rather than a != there. With the round, you'll get integer times, but if something ugly happens, and you skip a second, it'll run forever!
If an individual loop iteration does not take much time:
#!/usr/bin/env python3
from time import monotonic as timer
def my_function():
deadline = timer() + 10
while timer() < deadline:
......... #run this for 10 seconds
def my_next_function():
deadline = timer() + 5
while timer() < deadline:
......... #run this for 5 seconds
Otherwise, see How to limit execution time of a function call in Python.
I'm assuming you want to repeat the whole function until time is up, rather than trying to interrupt the function midway through it time is up (which would be more difficult). One nice solution is to use a decorator:
import time
def repeat(func):
def inner(*args, **kwargs):
if 'repeat_time' in kwargs:
stop = kwargs.pop('repeat_time') + time.time()
while time.time() <= stop:
func(*args, **kwargs)
else:
func(*args, **kwargs)
return inner
#repeat
def my_func():
# ...
my_func() # calls my_func once
my_func(repeat_time=10) # repeatedly calls my_func for 10 seconds
This code assumes you don't want to do anything with the return values from my_func, but can easily be adapted to collect the return values in case you do.
Or simpler if you do not need to pass any parameters to my_func:
def repeat_for(seconds, func):
stop = seconds + time.time()
while time.time() <= stop:
func()
def my_func():
# ...
repeat_for(10, my_func)