How to make Non-blocking timer in Python - python

i need your help.
I need a non-bloking timer, that allows me, in the period it's still counting, doing other tasks.
I need this function for my bot and obviously I don't want to block it all times I call this type of function which requires these timers.
So, in the past i used to use in Arduino (c++) the function millis() that in the same configuration seems not working well like
int t0 =0
int t1
void loop(){
t1= millis()
while (t1-t0 < 6000){
Serial.print(Timer!);
t0 = millis();}}
Do you have any advice for me? A code where I can start from?
Thanks!

The following will print "Timer" for 6 seconds:
import time
start_time = time.time() # returns number of seconds passed since epoch
current_time = time.time()
max_loop_time = 6 # 6 seconds
while (current_time - start_time) <= max_loop_time:
# do stuff
print("Timer")
current_time = time.time()

Okay, i found the solution by myself, trying to remember what i previously did on Arduino.
I based this answer from Adam Minas's one, but mine is quite different
So the expected behavior had to be:
print(something) every 5 seconds so:
import time
start_time = time.time() # returns number of seconds passed since epoch
#current_time = time.time()
print(start_time)
max_loop_time = 20 # 6 seconds
while True:
while (time.time() - start_time) > max_loop_time:
print("Timer")
start_time = time.time()
Then you can stop your while loop with break and other functions like
if == smth :
break

Related

Python 3.7 - How do I execute a loop with a start and stop time using datetime.now().strftime() on the minute?

I'm creating a loop which executes every 5 seconds, starting at the startTime variable and ending at the stopTime variable. However, the code below is disregarding the minutes within my startTime and endTime variables and only executing on the hour. For example, even though my startTime is '1130', the code is executing 11:05, rather than ending the loop. I have the same problem with the endTime variable. If the current time is 12:45, the code still executes even though the endTime variable is '1230'. The code will stop executing at '1300'.
frequency = 5
startTime = '1130'
endTime = '1230'
while True:
now = datetime.now().strftime('%H:%M:%S')
if startTime <= now <= endTime:
print('Loop is working. Time is: ',now)
time.sleep(frequency)
else:
print('Loop is stopped')
break
I live in Central Time, so I tried switching to Eastern timezone by modifying the "now" variable to:
now = datetime.now(timezone('US/Eastern')).strftime('%H:%M:%S.%f %Z')
but I still get the same problem when I substitute eastern times with startTime and endTime when using the eastern datetime.now().
Is executing code at a precise minute possible with strftime()?
EDIT: (this is now the answer to the real question (oops))
If you want to wait till for example 11:30 (which was the real question)
you can calculate the time (in seconds) the program should sleep (and let it sleep for that time):
def wait_till(hour, minute, second=0):
# get system time (and date)
now_time = datetime.datetime.now()
# create time point we are waiting for (this year, this month and this day)
wait_till_time = datetime.datetime(year=now_time.year, month=now_time.month, day=now_time.day, hour=hour, minute=minute, second=second)
# calculate time we want to wait for and convert to seconds
wait_for = (wait_till_time - now_time).total_seconds()
# check if it's going to be tomorrow (if we would sleep for a negative amount of seconds)
if wait_for < 0:
# add one day
wait_till_time = wait_till_time.replace(day=now_time.day+1)
# recalculate (not very beautiful, but i don't know a better way)
wait_for = (wait_till_time - now_time).total_seconds()
# printing this waiting time (in seconds)
print("waiting for",wait_for,"seconds")
# sleeping for that time
time.sleep(wait_for)
# printing the new now time, so we can see how accurate it is
print("its now",datetime.datetime.now())
and say for example:
wait_till(20, 24) # waiting till 20:24 (today)
and get:
waiting for 15.32297 seconds
its now 2019-03-11 20:24:00.003857
which is pretty darn close to what we wanted (20:24:00.000000) and this delay is probably only caused by the calculation lag of formatting the string.
(The old stuff ...)
if it's not important that it takes 100% 5s (but rather 100.04546642303467% --> it will get off a little bit every time) you can just do
import time
frequency = 5 #every 5 seconds
start_time = time.time()
while 1:
elspsed_time = time.time() - start_time
print(elspsed_time)
time.sleep(frequency)
but if you need the 100% you can try this autocorrecting solution:
import time
from threading import Timer
frequency = 5 #every 5 seconds
start_time = time.time()
def what_to_do_after_5s():
elapsed_time = time.time() - start_time
print(elapsed_time)
# next call
Timer(5.0 - (elapsed_time - int(elapsed_time)), what_to_do_after_5s, ()).start()
what_to_do_after_5s()
and we can see that it autocorrects:
0.0
5.000170707702637
10.000272989273071
15.000539064407349
20.001248836517334
25.00046443939209
30.000929355621338
35.00142860412598
40.0007688999176
45.00128436088562
50.00045442581177
55.000683069229126
60.00123882293701
65.00095415115356
70.0015127658844

Python - Accurate time.sleep

I am working on a project which accurate timer is really crucial. I am working on python and am using timer.sleep() function.
I noticed that timer.sleep() function will add additional delay because of the scheduling problem (refer to timer.sleep docs). Due to that issue, the longer my program runs, the more inaccurate the timer is.
Is there any more accurate timer/ticker to sleep the program or solution for this problem?
Any help would be appreciated. Cheers.
I had a solution similar to above, but it became processor heavy very quickly. Here is a processor-heavy idea and a workaround.
def processor_heavy_sleep(ms): # fine for ms, starts to work the computer hard in second range.
start = time.clock()
end = start + ms /1000.
while time.clock() < end:
continue
return start, time.clock()
def efficient_sleep(secs, expected_inaccuracy=0.5): # for longer times
start = time.clock()
end = secs + start
time.sleep(secs - expected_inaccuracy)
while time.clock() < end:
continue
return start, time.clock()
output of efficient_sleep(5, 0.5) 3 times was:
(3.1999303695151594e-07, 5.0000003199930365)
(5.00005983869791, 10.00005983869791)
(10.000092477987678, 15.000092477987678)
This is on windows. I'm running it for 100 loops right now. Here are the results.
(485.003749358414, 490.003749358414)
(490.0037919174879, 495.0037922374809)
(495.00382903668014, 500.00382903668014)
The sleeps remain accurate, but the calls are always delayed a little. If you need a scheduler that accurately calls every xxx secs to the millisecond, that would be a different thing.
the longer my program runs, the more inaccurate the timer is.
So, for example by expecting 0.5s delay, it will be time.sleep(0.5 - (start-end)). But still didn't solve the issue
You seem to be complaining about two effects, 1) the fact that timer.sleep() may take longer than you expect, and 2) the inherent creep in using a series of timer.sleep() calls.
You can't do anything about the first, short of switching to a real-time OS. The underlying OS calls are defined to sleep for at least as long as requested. They only guarantee that you won't wake early; they make no guarantee that you won't wake up late.
As for the second, you ought to figure your sleep time according to an unchanging epoch, not from your wake-up time. For example:
import time
import random
target = time.time()
def myticker():
# Sleep for 0.5s between tasks, with no creep
target += 0.5
now = time.time()
if target > now:
time.sleep(target - now)
def main():
previous = time.time()
for _ in range(100):
now = time.time()
print(now - previous)
previous = now
# simulate some work
time.sleep(random.random() / 10) # Always < tick frequency
# time.sleep(random.random()) # Not always < tick frequency
myticker()
if __name__ == "__main__":
main()
Working on Linux with zero knowledge of Windows, I may be being naive here but is there some reason that writing your own sleep function, won't work for you?
Something like:
import time
def sleep_time():
start_time = time.time()
while (time.time() - start_time) < 0.0001:
continue
end_time = time.time() + 60 # run for a minute
cnt = 0
while time.time() < end_time:
cnt += 1
print('sleeping',cnt)
sleep_time()
print('Awake')
print("Slept ",cnt," Times")

Wait between Function Calls

I am new to Python. I want to add wait between two function calls.
Below is the code snap, but with this code wait is not working. My code goes in to pause as soon as it reaches the first line of uploadFullstackZiptoCDN().
How Can I make sure that I have a pause of 5 minutes between the functions?
uploadFullstackZiptoCDN(fsartifactFile,fullStackgroup_ID,fsVersion,sdpIP,cdnIP)
makeRestCalls(ugdmHostIP,ipmessagingHostIP,cdnIP,fsVersion,fsartifactFile,'FullStack')
time.sleep(300)
makeappUpgradeZip(appartifactFile,appgroup_ID,appversion,sdpIP,cdnIP)
uploadZiptoCDN(cdnIP,appartifactFile,appversion)
Code below produces a delay which seems to be well-controlled.
It might likely be adapted to your needs.
Among other differences, it allows for more granularity in the start and stop times than time.sleep.
#!/usr/bin/python3
import time
t0 = time.time()
nsecs = 300
while True :
t1 = time.time()
if ( (t1 - t0) > nsecs ) :
break
print( t1 - t0 )

Accurate sleep/delay within Python while loop

I have a while True loop which sends variables to an external function, and then uses the returned values. This send/receive process has a user-configurable frequency, which is saved and read from an external .ini configuration file.
I've tried time.sleep(1 / Frequency), but am not satisfied with the accuracy, given the number of threads being used elsewhere. E.g. a frequency of 60Hz (period of 0.0166667) is giving an 'actual' time.sleep() period of ~0.0311.
My preference would be to use an additional while loop, which compares the current time to the start time plus the period, as follows:
EndTime = time.time() + (1 / Frequency)
while time.time() - EndTime < 0:
sleep(0)
This would fit into the end of my while True function as follows:
while True:
A = random.randint(0, 5)
B = random.randint(0, 10)
C = random.randint(0, 20)
Values = ExternalFunction.main(Variable_A = A, Variable_B = B, Variable_C = C)
Return_A = Values['A_Out']
Return_B = Values['B_Out']
Return_C = Values['C_Out']
#Updated other functions with Return_A, Return_B and Return_C
EndTime = time.time() + (1 / Frequency)
while time.time() - EndTime < 0:
time.sleep(0)
I'm missing something, as the addition of the while loop causes the function to execute once only. How can I get the above to function correctly? Is this the best approach to 'accurate' frequency control on a non-real time operating system? Should I be using threading for this particular component? I'm testing this function on both Windows 7 (64-bit) and Ubuntu (64-bit).
If I understood your question correctly, you want to execute ExternalFunction.main at a given frequency. The problem is that the execution of ExternalFunction.main itself takes some time. If you don't need very fine precision -- it seems that you don't -- my suggestion is doing something like this.
import time
frequency = 1 # Hz
period = 1.0/frequency
while True:
time_before = time.time()
[...]
ExternalFunction.main([...])
[...]
while (time.time() - time_before) < period:
time.sleep(0.001) # precision here
You may tune the precision to your needs. Greater precision (smaller number) will make the inner while loop execute more often.
This achieves decent results when not using threads. However, when using Python threads, the GIL (Global Interpreter Lock) makes sure only one thread runs at a time. If you have a huge number of threads it may be that it is taking way too much time for the program to go back to your main thread. Increasing the frequency Python changes between threads may give you more accurate delays.
Add this to the beginning of your code to increase the thread switching frequency.
import sys
sys.setcheckinterval(1)
1 is the number of instructions executed on each thread before switching (the default is 100), a larger number improves performance but will increase the threading switching time.
You may want to try python-pause
Pause until a unix time, with millisecond precision:
import pause
pause.until(1370640569.7747359)
Pause using datetime:
import pause, datetime
dt = datetime.datetime(2013, 6, 2, 14, 36, 34, 383752)
pause.until(dt)
You may use it like:
freqHz=60.0
td=datetime.timedelta(seconds=1/freqHz)
dt=datetime.now()
while true:
#Your code here
dt+=td
pause.until(dt)
Another solution for an accurate delay is to use the perf_counter() function from module time. Especially useful in windows as time.sleep is not accurate in milliseconds. See below example where function accurate_delay creates a delay in milliseconds.
import time
def accurate_delay(delay):
''' Function to provide accurate time delay in millisecond
'''
_ = time.perf_counter() + delay/1000
while time.perf_counter() < _:
pass
delay = 10
t_start = time.perf_counter()
print('Wait for {:.0f} ms. Start: {:.5f}'.format(delay, t_start))
accurate_delay(delay)
t_end = time.perf_counter()
print('End time: {:.5f}. Delay is {:.5f} ms'.
format(t_end, 1000*(t_end - t_start)))
sum = 0
ntests = 1000
for _ in range(ntests):
t_start = time.perf_counter()
accurate_delay(delay)
t_end = time.perf_counter()
print('Test completed: {:.2f}%'.format(_/ntests * 100), end='\r', flush=True)
sum = sum + 1000*(t_end - t_start) - delay
print('Average difference in time delay is {:.5f} ms.'.format(sum/ntests))`

Periodically execute function every n minutes while doing other stuffs

I want to basically update a variable value every 5 minutes by calling a function in python while doing other tasks if time is not 5 minutes. I tried to use strftime to keep time but got lost. Not sure what mistake I am making. Any help is much appreciated.
variable = 0
start_time = strftime("%M")
While True:
{do something here}
current_time = strftime("%M")
diff = int(start_time) - int(current_time)
if diff is 5 minutes:
function_call() #updates the variable
else:
Use the old variable value
If you want to an asynchronous function call take a look at: Timer Objects and use them as such (from the docs):
from threading import Timer
t = Timer(300.0, function_call)
t.start() # after 300 seconds, function_call will be called
Otherwise the simpler solution (without threads) is just to check the difference from time calls as such (as you were trying to do):
from time import time
start_time = time()
# do stuff
if time() - start_time > 300: # 300 secs
function_call()
So using the 2nd option your code could look like this:
from time import time
variable = 0
start_time = time()
While True:
{do something here}
current_time = time()
diff = current_time - start_time
if diff > 5*60:
function_call() #updates the variable
start_time = current_time
else:
Use the old variable value

Categories