Inconsistent results while measuring execution time of delayed loop - python

I have a pretty specific problem. I want to measure execution time of the generator loop (with the yield keyword). However, I don't know in what intervals next() will be called on this generator. This means I can't just get the timestamp before and after the loop. I thought getting the timestamp at the beginning and end of each iteration will do the trick but I'm getting very inconsistent results.
Here's the test code:
import time
def gen(n):
total = 0
for i in range(n):
t1 = time.process_time_ns()
# Something that takes time
x = [i ** i for i in range(i)]
t2 = time.process_time_ns()
yield x
total += t2 - t1
print(total)
def main():
for i in gen(100):
pass
for i in gen(100):
time.sleep(0.001)
for i in gen(100):
time.sleep(0.01)
if __name__ == '__main__':
main()
Typical output for me looks something like this:
2151918
9970539
11581393
As you can see it looks like the delay outside of the loop somehow influences execution time of the loop itself.
What is the reason of this behavior? How can I avoid this inconsistency? Maybe there's some entirely different way of doing what I'm trying to achieve?

You can switch the yield x and total += t2 - t1 lines to only count the time it takes to create x.
For more in dept also see: Behaviour of Python's "yield"

Related

Functions that stop after x time Python

I am working at a Python project, and I reached a point where I need a function to stop and return after a x time, that is passed as a parameter. A simple example:
def timedfunc(time_to_stop):
result = None
while (time_has_not_passed):
do()
return result
I explain:
When time has passed, timedfunc stops and interrupts everything in it, and jumps right to return result. So, what I need is a way to make this function work as long as possible (time_to_stop), and then to return the result variable, which is as accurate as possible (More time, more calculations, more accuracy). Of course, when time is out, also do() stops. To better understand, I say that the function is continuosly changing the value of result, and once the time has passed it returns the current value. (do() stands for all the calculations that change result)
I just made a simple example to better explain what I want:
def multiply(time):
result = 10
while time_has_not_passed:
temporary = result*10 #Actually much more time-consuming, also like 3 minutes.
temporary /= 11
result = temporary
return result
This explains what kind of calculations do() makes, and I need as many *10/11 as python can do in, for example, 0.5 sec.
I know that this pretty complicated, but any help would be great.
import time
start_time = time.time()
program()
if (time.time()-start_time)>0.5: #you can change 0.5 to any other value you want
exit()
It is something like this. you can put this if statement right inside your program function too.
maybe you can use:
time.sleep(x)
do()
# OR
now = time()
cooldown = x
if now + cooldown < time():
do()
if you want it to do something for a while
now = time()
needed_time = x
while now + needed_time > time():
do()

I am trying to make a alarm like feature app but it keeps waiting

I am trying to make a alarm like app where I want a list of things to happen when its time. But I am facing a bug. Time keeps waiting for previous time instead of going to next time in list.
t1 = dt.time(hour=17,minute=8)
t2 = dt.time(hour=18,minute=48)
timetable = [t1, t2]
for elt in timetable:
i_time = elt
#i_minute = i.minute
while True:
if i_time == dt.datetime.now().time():
#if i_hour == dt.datetime.now().hour and i_minute == dt.datetime.now().minute:
#current_time = tk.Label(text = dt.datetime.now())
#current_time.pack()
#playsound('media/ClassAlarm.mp3')
print("Its time")
break
The function works fine when it comes to t1 but if t1 is passed and current time is higher that t1 it should go to t2 and ring alarm. But it keeps waiting for t1 which will happen next day. it doesn't read t2 unless t1 is processed.
Ex. Current time 1:30 while t1 is 1:25 and t2 is 1:35. It doesn't ring at t2 but keeps waiting for t1 to happen again which has already happened.
I have tried to execute for loop in different way
for elt in timetable:
time = dt.datetime.now().time()
if time - elt < 0:
break
while(True):
if time == elt:
print("you did it")
I have also tried any() method. Which isn't helping exactly as well
current_hour = dt.datetime.now().hour
current_min = dt.datetime.now().minute
alarm = any(i.hour == current_hour and i.minute == current_min for i in timetable)
print(alarm)
I have tried posting question previously but wasn't able to explain properly. Hope this helps
Using == Operator To Compare Time Is Risky, Logically It Should Work But Somehow It's Better To Use <= Operator Which Eventually Compare If Your Time Is Greater Than The One Recorded In List! This Is Lot Safer Than Equality Which Trigger Only Once And Has No Guarantee To Work For A Split
-->Note: I Believe Those Function Generated Timestamp Of Different Format, Although They Represent Time And Are Useful But Since They Are In Different Format You Ain't Getting Equality Operator To Work (Bcz Even for Same Time And Date, Your Timestamp Gonna Be Different Although They Represent Same). To confirm this behavior you can write print variables of t1 and datetime.now and see if they are same.
Regarding Your Second Question You Can Have if/else statements to check for which time has been occured and most last time which has just been crossed, or you can run loop in reverse and check for timer (assuming late timers are in end of loop)
Sample Code:
for elt in timetable.reverse():
i_time = elt
while True:
if i_time <= dt.datetime.now().time():
print("Its time")
break

Python - running a program every 10 seconds, datetime.now() changes behavior

I was testing a program to do something every N seconds, but I bumped into a weird problem.
If I use something simple like this:
import time
def main():
start_t = time.time()
while(True):
if (time.time()-start_t)%10 == 0:
print("Test")
if __name__ == "__main__":
main()
the program works as expected, i.e. it prints "Test" every 10 seconds.
However, I made a small modification, because I need to check at every iteration the current date...if I change the program to this:
import time
from datetime import datetime
def main():
start_t = time.time()
path_screenshots = "screenshots"
while(True):
path_screenshots_today = f"{path_screenshots}/{datetime.now().strftime('%Y_%m_%d')}/"
if (time.time()-start_t)%10 == 0:
print(f"Checking folder {path_screenshots_today}...")
if __name__ == "__main__":
main()
I would expect the program to print "Checking folder {path_screenshots_today}" every 10 seconds again, but instead it keeps running, without printing anything.
I understand that the result of the operation (time.time()-start_t)%10 is never precisely equal to 0, which might be creating the issue...but then, why does it even work in the first case?
I suspect it is working in the first case because the loop is running fast enough that it happens to line up. The lag created by creating path_screenshots_today (particularly the datetime.now() call) causes it not to line up as often. To actually do what you want, try:
import time
from datetime import datetime
def main():
last = time.time()
path_screenshots = "screenshots"
while True:
path_screenshots_today = f"{path_screenshots}/{datetime.now().strftime('%Y_%m_%d')}/"
if time.time() - last >= 10:
last = time.time()
print(f"Checking folder {path_screenshots_today}...")
if __name__ == "__main__":
main()
The first case works because the time is checked frequently enough, which does not happen in the second case because of the delay introduced by the string formatting. A more robust way is the following:
start_t = time.time()
while True:
path_screenshots_today = f"{path_screenshots}/{datetime.now().strftime('%Y_%m_%d')}/"
tt = time.time()
if tt - start_t >= 10:
print(f"Checking folder {path_screenshots_today}...")
start_t = tt # set last check time to "now"
And an even better way would be:
while True:
path_screenshots_today = f"{path_screenshots}/{datetime.now().strftime('%Y_%m_%d')}/"
print(f"Checking folder {path_screenshots_today}...")
time.sleep(10)
This avoids "busy waiting", i.e. keeping the CPU running like crazy.
It's a coincidence of how often the check is happening. If you actually loop over and print your value, you'll notice it's floating point:
while(True):
print('Current value is, ', (time.time()-start_t)%10)
You'll see output like this:
Current value is, 0.45271849632263184
Current value is, 0.45272231101989746
Given that you're doing so little in your loop, the odds are good that you'll coincidentally do that evaluation when the current value is exactly 0.0. But when you add some extra computation, even just the string formatting in datetime, each iteration of your loop will take a little longer and you might just happily skip over 0.0.
So strictly speaking, you should cast your value to an int before comparing it to 0. Eg, int((time.time() - start_t) % 10) == 0. That will be true for an entire second, until the modulus value is once again not zero, a second after it's first true.
A better solution, however, is to probably just use the time.sleep() function. You can call time.sleep to sleep for a number of seconds:
time.sleep(10) # Sleep for 10 seconds

Need to restart loop

Still a NOOB in Python. Get stuck many times.
Script runs 3 sequencies, one after the other, each for 20 seconds.
Each sequence has a while loop. and a time out statement.
Then it starts the next loop, and so on till the end of end of the
3rd loop. Then it quits. I would like to start again from the top.
I probably have too many while loops.
#!/usr/bin/env python
# Import required libraries
import time
# More setup
# Choose a matrix to use
mat = mat1
t_end = time.time() + 20
#Start loop
while time.time() < t_end:
# code
# loop timeout
# 2 more loops follow just like first one, except matrix becomes
mat = mat2
mat = mat3
As others have already commented, you should do any repetitive tasks within a function. In Python, functions are defined using the "def" keyword. Using a function, it could be done as follows:
import time
# Replace these dummy assignments with real code
mat1 = "blah"
mat2 = "rhubarb"
mat3 = "custard"
def processMatrix(matrix, seconds=20):
t_end = time.time() + seconds
while time.time() < t_end:
pass # 'pass' does nothing - replace with your real code
processMatrix(mat1)
processMatrix(mat2)
processMatrix(mat3)
Note that I've also included the time/seconds as a parameter in the function. This gives you more flexibility, in case you wanted to run for different times for testing or different times for each matrix, etc. However, I've done it with a default value of 20 so that you don't need to include it in the function call. If you do want to override the default you could call, eg,
processMatrix(mat1, 5)
instead of,
processMatrix(mat1)

Zero return in measuring time of function

import time
def find(a):
count = 0
for item in a:
count = count + 1
if item == 2:
return count
a = [7,4,5,10,3,5,88,5,5,5,5,5,5,5,5,5,5,55,
5,5,5,5,5,5,5,5,5,5,5,5,55,5,5,5,5,5,
5,5,5,5,5,2,5,5,5,55,5,55,5,5,5,6]
print (len(a))
sTime = time.time()
print (find(a))
eTime = time.time()
ave = eTime - sTime
print (ave)
I want measure the execution time of this function
My print (ave) returns 0; why?
To accurately time code execution you should use the timeit, rather than time. timeit easily allows the repetition of code blocks for timing to avoid very near zero results (the cause of your question)
import timeit
s = """
def find(a):
count = 0
for item in a:
count = count + 1
if item == 2:
return count
a = [7,4,5,10,3,5,88,5,5,5,5,5,5,5,5,5,5,55,5,5,5,5,5,5,5,5,5,5,5,5,55,5,5,5,5,5,5,5,5,5,5,2,5,5,5,55,5,55,5,5,5,6]
find(a)
"""
print(timeit.timeit(stmt=s, number=100000))
This will measure the amount of time it takes to run the code in multiline string s 100,000 times. Note that I replaced print(find(a)) with just find(a) to avoid having the result printed 100,000 times.
Running many times is advantageous for several reasons:
In general, code runs very quickly. Summing many quick runs results in a number which is actually meaningful and useful
Run time is dependent on many variable, uncontrollable factors (such as other processes using computing power). Running many times helps normalize this
If you are using timeit to compare two methodologies to see which is faster, multiple runs will make it easier to see the conclusive result
I'm not sure, either; I get a time about 1.4E-5.
Try putting the call into a loop to measure more iterations:
for i in range(10000):
result = find(a)
print(result)

Categories