wait function that uses while - python

I just wrote a function that looked like this:
def block_for(seconds):
"""Wait at least seconds, this function should not be affected by the computer sleeping."""
end_time = datetime.datetime.now() + datetime.timedelta(seconds)
while datetime.datetime.now() < end_time:
pass
Can anything bad come of this? Should there ideally be something inside the while loop?

time.sleep(seconds) seconds does just that without burning through CPU cycles. your loop keeps the CPU fully busy. i do not know for you but i consider this bad.

maybe putting time.sleep(1) in the while loop will require less cycles? Or
def block_for(seconds):
"""Wait at least seconds, this function should not be affected by the computer sleeping."""
end_time = datetime.datetime.now() + datetime.timedelta(seconds=seconds)
while datetime.datetime.now() < end_time - datetime.timedelta(seconds=1):
time.sleep(1)
while datetime.datetime.now() < end_time:
pass

Related

Schedule an iterative function every x seconds without drifting

Complete newbie here so bare with me. I've got a number of devices that report status updates to a singular location, and as more sites have been added, drift with time.sleep(x) is becoming more noticeable, and with as many sites connected now it has completely doubles the sleep time between iterations.
import time
...
def client_list():
sites=pandas.read_csv('sites')
return sites['Site']
def logs(site):
time.sleep(x)
if os.path.isfile(os.path.join(f'{site}/target/', 'hit')):
stamp = time.strftime('%Y-%m-%d,%H:%M:%S')
log = open(f"{site}/log", 'a')
log.write(f",{stamp},{site},hit\n")
log.close()
os.remove(f"{site}/target/hit")
else:
stamp = time.strftime('%Y-%m-%d,%H:%M:%S')
log = open(f"{site}/log", 'a')
log.write(f",{stamp},{site},miss\n")
log.close()
...
if __name__ == '__main__':
while True:
try:
client_list()
with concurrent.futures.ThreadPoolExecutor() as executor:
executor.map(logs, client_list())
...
I did try adding calculations for drift with this:
from datetime import datetime, timedelta
def logs(site):
first_called=datetime.now()
num_calls=1
drift=timedelta()
time_period=timedelta(seconds=5)
while 1:
time.sleep(n-drift.microseconds/1000000.0)
current_time = datetime.now()
num_calls += 1
difference = current_time - first_called
drift = difference - time_period* num_calls
if os.path.isfile(os.path.join(f'{site}/target/', 'hit')):
...
It ends up with a duplicate entries in the log, and the process still drifts.
Is there a better way to schedule the function to run every x seconds and account for the drift in start times?
Create a variable equal to the desired system time at the next interval. Increment that variable by 5 seconds each time through the loop. Calculate the sleep time so that the sleep will end at the desired time. The timings will not be perfect because sleep intervals are not super precise, but errors will not accumulate. Your logs function will look something like this:
def logs(site):
next_time = time.time() + 5.0
while 1:
time.sleep(time.time() - next_time)
next_time += 5.0
if os.path.isfile(os.path.join(f'{site}/target/', 'hit')):
# do something that takes a while
So I managed to find another route that doesn't drift. The other method still drifted over time. By capturing the current time and seeing if it is divisible by x (5 in the example below) I was able to keep the time from deviating.
def timer(t1,t2)
return True if t1 % t2 == 0 else False
def logs(site):
while 1:
try:
if timer(round(time.time(), 0), 5.0):
if os.path.isfile(os.path.join(f'{site}/target/', 'hit')):
# do something that takes a while
time.sleep(1) ''' this kept it from running again immediately if the process was shorter than 1 second. '''
...

How can I write a loop to make the timer run every two seconds

I have a question on how I am able to set the timer so that every time it exits the loop it sets the time back to 2 seconds. The problem is that the first time the sound works after 2 seconds, the next times it is executed immediately. Thank you very much in advance for any advice.
This is my code:
time = 2
while time > 0:
timer = datetime.timedelta(seconds=time)
time -= 1
duration = 1000
freq = 440
winsound.Beep(freq, duration)
I am not sure if you meant that, but for me it seems like you just want to wait 2 seconds before executing the next steps. You can do that like so:
import time
while True:
time.sleep(2) # waits 2 seconds
winsound.Beep(440, 1000)
Anyways I don't recommend you to use a plain infinite loop, without a break statement. Therefore I recommend you to add one, like down below.
import time
while True:
time.sleep(2) # waits 2 seconds
winsound.Beep(440, 1000)
if True: # break on a specific statment
break
Edit: As CrazyChucky mentioned in the comments, this approach should work fine in most of the cases, but it can end up being more than two seconds sometimes. Therefore you should work with timedeltas or take a look at scheduler.
To be more accurate as possible use:
import time
timer = 0
step = 2
t0 = time.time()
while True:
timer = time.time() - t0
wait = step - timer
time.sleep(wait)
print(time.time())
winsound.Beep(freq, duration)
t0 = time.time()
This script take in count the execution time of script lines for your computer.
You just have to reinitialize the time at the end of the loop
time = 2
while True:
timer = datetime.timedelta(seconds=time)
time -= 1
duration = 1000
freq = 440
if time == 0:
time = 2
break
winsound.Beep(freq, duration)

Whats the simplest way to run my program for one minute then pause it for one minute

I have some code here that prints a line one time every minute but I want to change it so it prints the message for one minute straight then pauses for one minute indefinitely. How do I achieve this?
import time
while True:
print("This prints once a minute.")
time.sleep(60) # Delay for 1 minute (60 seconds).
To print the message constantly for a minute, then wait for a minute, then repeat indefinitely, you can use the following:
import time
while True:
s = time.time()
while time.time() < s + 60:
print("Message")
time.sleep(60)
If you want to print the message every second for one minute. You can do something like below:
import time
original_time = time.time()
while time.time() < original_time + 60:
print("This prints every second for one minute")
time.sleep(1)
Is that what you are looking for?
You can track when you start your minute, and then wait 60 seconds. Each 60 seconds you switch the state of is_printing.
import time
is_printing = False
while True:
is_printing = not is_printing
start_time = time.time()
while time.time() - start_time < 60:
if is_printing:
print("Printing this for a minute.")

Python : Basic countdown timer & function() > int()

I'm trying to ucreate a timer function that runs in the background of my code and make it so I can use/check the time. What I mean by use/check, I'm trying to make it so I can call upon that timer function and use it as integer.
This is the code I currently have:
def timer():
for endtime in range(0, 15):
print(15 - endtime)
time.sleep(1)
def hall():
timer()
while (timer > 0):
do something
Currently only using print(15 - endtime) for confirmation it is counting down.
But what the code does now is execute the countdown and that's it, it never touches the while loop. And of course the last issue is I can't set a function to an int. So I'm looking for some way where I can check where the timer is at and use it in that while loop.
The way you do it, you'll going to have to use multithread.
Here is another, simpler approach :
On your script beginning, set a time_start variable with the number of seconds since the epoch using time.time()
Then when you need the number of elapsed seconds, use time.time() - time_start :
t_start = time.time()
# do whatever you'd like
t_current = int(time.time()-t_start) # this way you get the number of seconds elapsed since start.
You can put that in a function as well, defining t_start as a global variable.
import time
t_start = time.time()
def timer():
global t_start
print(str(int(time.time()-t_start)))
print('start')
time.sleep(2)
timer()
time.sleep(3)
timer()
import time
def timer(tim):
time.sleep(1)
print tim
def hall():
tim = 15
while (tim > 0):
print 'do something'
timer(tim)
tim-=1
Not the cleanest solution, but it will do what you need.
The problem with your code is that when you run hall(), Python first executes the whole of timer() (i.e. the whole for loop), and then moves on with the rest of the code (it can only do one thing at a time). Thus, by the time it reaches the while loop in hall(), timer is already 0.
So, you're going to have to do something about that timer so that it counts down once, and then it moves on to the do something part.
Something that you can do is this:
def hall():
for a in range(0, 15):
print(15 - a)
# do something
time.sleep(1)
This should work just fine (if you're only executing hall 15 times), and condenses your code to just one function.

How do you use KeyboardInterrupt without a try statement

I am trying to make a basic wage timer for my brother who just got a job... What I wanted to have was a while loop running the code waiting for someone to press enter (or some other key) ends the loop and give the current wage. I was hoping to KeyboardInterrupt but if there is an easier way to do it I would love to hear about it. How could I do this?
a keyboard interrupt is generated only when someone hits ctrl-C or similar.
it sounds like your plan was to have code something like:
from time import sleep
wage = 0
try:
while True:
wage = wage + hourly_rate
sleep(60 * 60) # an hour in seconds
except KeyboardInterrupt:
print('you earned', wage)
and then have someone hit ctrl-C? which would work with a try/except. but if you want someone just to hit the return key then instead of adding things up, do some maths:
from time import time
start = time() # time in seconds from some arbitrary date in 1970 (it's a standard)
input('hit return to get your wage!')
end = time()
elapsed = end - start # time that has passed in seconds between start and end
wage = hourly_rate * elapsed / (60 * 60) # convert from hourly
print('you earned', wage)
the first version is a bit optimistic as it adds each hour at the start. the second is more accurate.
ps congrats to your brother!

Categories

Resources