How do I sched a repeat timer for 5 min intervals. Which fire at 00 seconds, then repeat at 00. Ok, not hard real-time but as close as possible with sys lags. Trying to avoid a build up in lags and get near 00.
Lang: Python, OS: WinXP x64
System has 25ms resolution.
Any code would be helpful, tia
I don't know how to do it any more accurately than with threading.Timer. It's "one-shot", but that just means the function you schedule that way must immediately re-schedule itself for another 300 seconds later, first thing. (You can add accuracy by measuring the exact time with time.time each time and varying the next scheduling delay accordingly).
Try and compare the time printouts of these two code samples:
Code Sample 1
import time
delay = 5
while True:
now = time.time()
print time.strftime("%H:%M:%S", time.localtime(now))
# As you will observe, this will take about 2 seconds,
# making the loop iterate every 5 + 2 seconds or so.
## repeat 5000 times
for i in range(5000):
sum(range(10000))
# This will sleep for 5 more seconds
time.sleep(delay)
Code Sample 2
import time
delay = 5
while True:
now = time.time()
print time.strftime("%H:%M:%S", time.localtime(now))
# As you will observe, this will take about 2 seconds,
# but the loop will iterate every 5 seconds because code
# execution time was accounted for.
## repeat 5000 times
for i in range(5000):
sum(range(10000))
# This will sleep for as long as it takes to get to the
# next 5-second mark
time.sleep(delay - (time.time() - now))
Related
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
I have a python program which I want to execute exactly 30 seconds before every 5th Minute and need to run for 30 seconds only.
Rather than looping and testing if it's the right time over and over again, it's better to calculate the amount of time needed to wait, and sleep until then so the processor can go off and do other things. To do this we still use the datetime module and just a bit of simple math.
from datetime import datetime as dt
from time import sleep
#Calculating sleep interval
t = dt.now()
#seconds in the hour
sec = t.second + t.minute*60
#seconds since the last 5 min interval
sec = sec % 300
#until the next 5 min interval
sec = 300 - sec
#30 sec before that
sec = sec - 30
#if negative we're within 30 sec of 5 minute interval so goto next one
if sec < 0:
sec = sec + 300
sleep(sec)
while True: #loop forever
#with a little re-arranging and boolean math, this can all be condensed to:
t = dt.now()
s = (t.second + 60*t.minute) % 300
sleep(270 - s + 300 * (s >= 270))
#yourFunction()
For very simple cases this should work. If at any point your program crashes, or if the computer re-boots, or a myriad of other reasons, It would be better to use something built in to the OS which will re-start the program automatically, and can handle other conditions such as setting sleep timers, or only executing if a particular user is logged in. On Windows this is task scheduler, on Linux this is typically cron, and OSX is launchd (at least according to developer.apple.com)
If you're running this code indefintley, I'd suggest you look at following Aaron's adivce at look at superuser.com, apple.stackexchange.com or askubuntu.com.
However, if you were going to write this in Python, you could use the datetime module and find the time that's elapsed.
from datetime import datetime
import time
def your_function(t1):
i = 0
# For the next 30 seconds, run your function
while (datetime.now() - t1).seconds =< 30:
i += 1
print(i)
time.sleep(1)
# Run indefintely
while True:
# Record the current time
t1 = datetime.now()
while t1:
# Find the elapsed time in seconds
# If the difference is 270 seconds (4 minutes and 30 seconds)
if (datetime.now()-t1).seconds == 270:
your_function(t1)
# Remove t1 and start at the top of the loop again
t1 = None
I'm trying to make a simple timer which prints the time remaining every second.
for k in range(100):
print(100-k)
t.sleep(1)
#output
#100
#99
#98
#...
#1
However, this will take slightly longer than 100 seconds, because there will be a delay added when print() is used. For long periods, this is slightly noticeable. Is there a way to account for this, and accurately display the time every second? I know I could just sleep(100), but this wouldn't let the time left be printed.
import time
start_time=time.time()
for k in range(25):
print(25-k)
time.sleep(1)
print("it took "+str(float(time.time()-start_time)*1000)+" Milliseconds")
the output with print is: it took 26412.75382041931 Milliseconds
the output without print : it took 25053.035020828247 Milliseconds
it should have been just 25000 milliseconds but it is not
printing will take time, even reading the code takes time
point is don't expect accurate timing with time.sleep() !!!
You can use time.time() to measure elapsed time.
import time
start_time = time.time()
for k in range(100):
# k seconds SHOULD be elapsed at this point
print(100 - k)
slept_time = time.time() - start_time
time.sleep(1 + k-slept_time)
Using time.sleep will never give you the accurate time for your timer, since the time it takes is the one second sleep time + printing time, you can use threading.Timer to get more accurate results. https://repl.it/Hwkt :
import threading, time
start_time=time.time()
def count_loop(counter):
if counter <= 0:
print("it took "+str(float(time.time()-start_time)*1000)+" Milliseconds")
return
threading.Timer(1.0, count_loop, args=[counter-1]).start()
print(counter)
count_loop(100)
This is still not accurate, but with only very minimum offset, only 45 ms. However, when using time.sleep from legendisback's example, there is apparently 81 ms delay. https://repl.it/HwlK
I'd like to create a revenue counter for the sales team at work and would love to use Python. E.g. Joe Bloggs shifts his target from 22.1 to 23.1 (difference of 1.0.) I'd like the counter to tick evenly from 22.1 to 23.1 over an hour.
I've created this script, which works fine for counting a minute (runs 2 seconds over the minute); however, when it's supposed to run for an hour, it runs for 47 minutes.
Question: Does anyone know why it runs faster when I set it to an hour? Is sleep.time inaccurate?
import time
def rev_counter(time_length):
time_start = (time.strftime("%H:%M:%S"))
prev_pp = 22.1
new_pp = 23.1
difference = new_pp - prev_pp
iter_difference = (difference / 100000.) # Divide by 100,000 to show 10 decimal places
time_difference = ((time_length / difference) / 100000.)
i = prev_pp
while i < new_pp:
print("%.10f" % i)
i = i + iter_difference
time.sleep(time_difference)
time_end = (time.strftime("%H:%M:%S"))
print "Time started at", time_start
print "Time ended at", time_end
rev_counter(60) # 60 seconds. Returns 62 seconds
rev_counter(600) # 10 minutes. Returns 10 minutes, 20 secs
rev_counter(3600) # 1 hour. Returns 47 minutes
Please note this quote from the Python documentation for time.sleep()
The actual suspension time may be less than that requested because any
caught signal will terminate the sleep() following execution of that
signal's catching routine. Also, the suspension time may be longer
than requested by an arbitrary amount because of the scheduling of
other activity in the system.
As a suggestion, if faced with this problem, I would use a variable to track the time that the interval starts. When sleep wakes up, check to see if the expected time has elapsed. If not, restart a sleep for the difference, etc.
First of all, your loop doesn't only contain sleep statements -- the things you do between calling time.sleep take time, too, so if you do 10 repetions, you'll spent only 10% of the time doing these compared to when you have 100 iterations through your loop.
Is sleep.time inaccurate?
Yes. Or well. Quite.
I come from a real-time signal processing background. PC clocks are only somewhat accurate, and the time you spend in your OS, your standard libraries, your scripting language run time and your scripting logic between the point in time when a piece of hardware notifies you that your time has elapsed and the point in time your software notices is significant.
I just noticed time.sleep taking way too long (5-30000 times longer for input values between .0001 to 1 second), and searching for an answer, found this thread. I ran some tests and it is consistently doing this (see code and results below). The weird thing is, I restarted, then it was back to normal, working very accurately. When code started to hang it was time.sleep taking 10000 times too long?!
So a restart is a temporary solution, but not sure what the cause is/ permanent solution is.
import numpy as np
import time
def test_sleep(N,w):
data = []
for i in xrange(N):
t0 = time.time()
time.sleep(w)
t1 = time.time()
data.append(t1-t0)
print "ave = %s, min = %s, max = %s" %(np.average(data), np.min(data), np.max(data))
return data
data1 = test_sleep(20,.0001)
Out: ave = 2.95489487648, min = 1.11787080765, max = 3.23506307602
print data1
Out: [3.1929759979248047,
3.121081829071045,
3.1982388496398926,
3.1221959590911865,
3.098078966140747,
3.131525993347168,
3.12644100189209,
3.1535091400146484,
3.2167508602142334,
3.1277999877929688,
3.1103289127349854,
3.125699996948242,
3.1129801273345947,
3.1223208904266357,
3.1313750743865967,
3.1280829906463623,
1.117870807647705,
1.3357980251312256,
3.235063076019287,
3.189779043197632]
data2 = test_sleep(20, 1)
Out: ave = 9.44276217222, min = 1.00008392334, max = 10.9998381138
print data2
Out: [10.999573945999146,
10.999622106552124,
3.8115758895874023,
1.0000839233398438,
3.3502109050750732,
10.999613046646118,
10.99983811378479,
10.999617099761963,
10.999662160873413,
10.999619960784912,
10.999650955200195,
10.99962306022644,
10.999721050262451,
10.999620914459229,
10.999532222747803,
10.99965500831604,
10.999596118927002,
10.999563932418823,
10.999600887298584,
4.6992621421813965]
I'm looking at creating a randomizing script in Python to execute a loop over a specific amount of time. If I wanted to run a loop 100 times within 5 days at random times within that 5 days, what would be the best way to go about it?
Pick a hundred uniformly distributed random points along the interval and sleep between them:
import random, time
DURATION = 5 * 86400 # five days
EXECS = 100
now = time.time()
points = sorted(random.random() * DURATION + now
for i in xrange(EXECS))
for p in points:
now = time.time()
if p > now:
time.sleep(p - now)
# run your loop here
You could "pre-plan" your randomized times to get the perfect fit in your time range. This assumes your loop time is insignificant in the scale of days (for 100 runs). You would need to add something if you wanted to be really exact
import random, time
def Rand_Run(func, time_range, num_runs):
# time range passed as days / convert to seconds
time_range = time_range*3600*24
# create a list of random numbers and a scaling factor for your time period
r_items = [random.random() for i in xrange(num_runs)]
r_scale = time_range/sum(r_items)
# create the list of time delays between runs
r_time_delays = (r_item*r_scale for r_item in r_items)
# run the function between random time delays
for r_time_delay in r_time_delays:
func()
time.sleep(r_time_delay)
NOT Python, but some idea:
duration = 5*24*60*60 //duration in seconds
for i = 0 to 99
array(i)=rand()*duration
end
sort array
counter=0
while time_elapsed<duration
if (time_elapsed>=array(counter))
DO SOMETHING
counter=counter+1
end
end