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
Related
Hi I make a app and want to know can we use random module to generate a random number which will change every 24 hours?
Thanks for help.
You can reseed random by using a count of days since a fixed date:
from datetime import datetime
import random
d0 = datetime(2008, 8, 18) # Pick an arbitrary date in the past
d1 = datetime.now()
delta = d1 - d0
print(delta.days)
random.seed(delta.days)
print(random.randint(1,10))
This will mean that print(random.randint(1,10)) will produce the same number anytime you run this today, but a likely different number tomorrow.
The delta section of this code was copied from this answer on stackoverflow.
Well, you can make use random and datetime module.
Here is the sample code:
import random, datetime
x = datetime.datetime.today().strftime("%Y:%m:%d")
random.seed(x)
r_int = random.randint(1, 100)
print(r_int)
Output:
73
Solutions based on reseeding the PRNG are effectively using the seed function as your random number generator rather than the PRNG state update algorithm. Because of this, there are no guarantees regarding the distributional properties of the result, whereas a good PRNG yields a sequence of values which pass numerous statistical tests for uniformity and lack of serial correlation.
The following solution wraps things up as a generator using yield, but the value to be yielded is only updated after the requisite period of time has passed, regardless of how many calls are made to the generator. If your app is intended to run for a multi-day extended period and you care about the distributional characteristics, I'd suggest something like this:
from datetime import datetime, timedelta
from random import randint # , seed
import time
def durable_randint(*, low = 1, high = 100, duration = timedelta(days = 1)):
assert isinstance(duration, timedelta), 'duration must be a "timedelta"!'
today = datetime.now()
# seed(today.strftime("%Y:%m:%d"))
last = today - 2 * duration
while True:
now = datetime.now()
if now - last > duration:
x = randint(low, high)
last = datetime.now()
yield x
if "__main__" == __name__:
# The following is overriding the default duration of one day.
# It will run for 45 seconds (15 iterations of 3 seconds),
# changing the value generated every 10 seconds.
gen = durable_randint(duration = timedelta(seconds = 10)) # lazy generator
for _ in range(15):
print(gen.__next__()) # next iteration of the generator
time.sleep(3)
Uncommenting the lines involving seed will yield consistent results across multiple independent runs if the resolution is one day.
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 am trying to log data at with a high sampling rate using a Raspberry Pi 3 B+. In order to achieve a fixed sampling rate, I am delaying the while loop, but I always get a sample rate that is a little less than I specify.
For 2500 Hz I get ~2450 Hz
For 5000 Hz I get ~4800 Hz
For 10000 Hz I get ~9300 Hz
Here is the code that I use to delay the while loop:
import time
count=0
while True:
sample_rate=5000
time_start=time.perf_counter()
count+=1
while (time.perf_counter()-time_start) < (1/sample_rate):
pass
if count == sample_rate:
print(1/(time.perf_counter()-time_start))
count=0
I have also tried updating to Python 3.7 and used time.perf_counter_ns(), but it does not make a difference.
The problem you are seeing is because your code is using the real time each time in the loop when it starts each delay for the period duration - and so time spent in untimed code and jitter due to OS multitasking accumulates, reducing the overall period below what you want to achieve.
To greatly increase the timing accuracy, use the fact that each loop "should" finish at the period (1/sample_rate) after it should have started - and maintain that start time as an absolute calculation rather than the real time, and wait until the period after that absolute start time, and then there is no drift in the timing.
I put your timing into timing_orig and my revised code using absolute times into timing_new - and results are below.
import time
def timing_orig(ratehz,timefun=time.clock):
count=0
while True:
sample_rate=ratehz
time_start=timefun()
count+=1
while (timefun()-time_start) < (1.0/sample_rate):
pass
if count == ratehz:
break
def timing_new(ratehz,timefun=time.clock):
count=0
delta = (1.0/ratehz)
# record the start of the sequence of timed periods
time_start=timefun()
while True:
count+=1
# this period ends delta from "now" (now is the time_start PLUS a number of deltas)
time_next = time_start+delta
# wait until the end time has passed
while timefun()<time_next:
pass
# calculate the idealised "now" as delta from the start of this period
time_start = time_next
if count == ratehz:
break
def timing(functotime,ratehz,ntimes,timefun=time.clock):
starttime = timefun()
for n in range(int(ntimes)):
functotime(ratehz,timefun)
endtime = timefun()
# print endtime-starttime
return ratehz*ntimes/(endtime-starttime)
if __name__=='__main__':
print "new 5000",timing(timing_new,5000.0,10.0)
print "old 5000",timing(timing_orig,5000.0,10.0)
print "new 10000",timing(timing_new,10000.0,10.0)
print "old 10000",timing(timing_orig,10000.0,10.0)
print "new 50000",timing(timing_new,50000.0,10.0)
print "old 50000",timing(timing_orig,50000.0,10.0)
print "new 100000",timing(timing_new,100000.0,10.0)
print "old 100000",timing(timing_orig,100000.0,10.0)
Results:
new 5000 4999.96331002
old 5000 4991.73952992
new 10000 9999.92662005
old 10000 9956.9314274
new 50000 49999.6477761
old 50000 49591.6104893
new 100000 99999.2172809
old 100000 94841.227219
Note I didn't use time.sleep() because it introduced too much jitter. Also, note that even though this minimal example shows very accurate timing even up to 100khz on my Windows laptop, if you put more code into the loop than there is time to execute, the timing will run correspondingly slow.
Apologies I used Python 2.7 which doesn't have the very convenient time.perf_counter() function - add an extra parameter timefun=time.perf_counter() to each of the calls to timing()
I think you can fix this pretty easily by rearranging your code as such:
import time
count=0
sample_rate=5000
while True:
time_start=time.perf_counter()
# do all the real stuff here
while (time.perf_counter()-time_start) < (1/sample_rate):
pass
This way python does the waiting after you execute the code, rather than before, so the time the interpreter takes to run it will not be added to your sample rate. As danny said, it's an interpreted language so that might introduce timing inconsistencies, but this way should at least decrease the effect you are seeing.
Edit for proof that this works:
import sys
import time
count=0
sample_rate=int(sys.argv[1])
run_start = time.time()
while True:
time_start=time.time()
a = range(10)
b = range(10)
for x in a:
for y in b:
c = a+b
count += 1
if count == sample_rate*2:
break
while (time.time()-time_start) < (1.0/sample_rate):
pass
real_rate = sample_rate*2/(time.time()-run_start)
print real_rate, real_rate/sample_rate
So the testing code does a solid amount of random junk for 2 seconds and then prints the real rate and the percentage of the actual rate that turns out to be. Here's some results:
~ ><> python t.py 1000
999.378471674 0.999378471674
~ ><> python t.py 2000
1995.98713838 0.99799356919
~ ><> python t.py 5000
4980.90553757 0.996181107514
~ ><> python t.py 10000
9939.73553783 0.993973553783
~ ><> python t.py 40000
38343.706669 0.958592666726
So, not perfect. But definitely better than a ~700Hz drop at a desired 10000. The accepted answer is definitely the right one.
Could someone please give me some help with limiting a loop to N iterations per minute in Python.
Lets say I have
limit = 5
for items in recvData:
# > limit iterations in past minute? -> sleep for 60 seconds from last iterations before proceeding? #
... do work ...
How would I do the time check / sleeping to give the correct flow. I'm not worried about blocking the executing thread/process while it waits.
Thanks
It should be noted that this is not "hard real time" code. this will be off slightly because of OS scheduling and the like. That being said, unless you know that you need hard real time, this should suffice.
import time
limit = 5
starttime = time.time()
for i, item in enumerate(recvData):
if not i + 1 % limit:
sleeptime =starttime + 60 - time.time()
if sleeptime > 0:
time.sleep(sleeptime)
starttime = time.time()
#processing code
Use grouper from the itertools recipes, combined with a time check.
import itertools, datetime, time
limit = 5
def grouper(n, iterable, fillvalue=None):
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return itertools.izip_longest(fillvalue=fillvalue, *args)
for items in grouper(limit, recvData):
prev_minute = datetime.datetime.now().minute
for item in items:
# do stuff
_, _, _, _, minute, second, _ = datetime.datetime.now()
if minute == prev_minute:
time.sleep( 60 - second )
This very much depends on the type of work you're doing inside the loop and on how accurate you want this mechanism to work.
ATM I can come up with 2 possible schemes:
If one iteration takes about constant time than you could calculate an average from the first few iterations and "sleep" for 1 - iterationTime afterwards.
Otherwise, you can poll the time and recalculate the average every step (or a few steps).
Depending on the standard deviation of your single loop execution times both scheme can work quite well, but if the execution times are very varying, neither of them will. Also, if you want evenly distributed loop cycles and not only keep the average/min you have to distribute the sleep-s and do one after each iteration.
I am not familiar enough with Python to know how expensive is to query the time and what other Python-specific issues might pop up with sleep-ing, though.
This would be the most appropriate answer :
What's a good rate limiting algorithm?
I especially like the second answer using the decorator!
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))