matches = []
done = []
for item in matches:
dofunctioneveryloop()
done.extent(item)
dofunctiononce5min()
How can I execute dofunctiononce5min() inside this loop once 5 minute? This is backup to file function is this possible?
Not sure I understood the question. I'll assume that you want this function to be executed only once every five minutes, no matter how often it is really called.
This might be overkill, but why not use a decorator? This will create a new function for the 'decorated' function that will execute the original function if X seconds have passed since the last execution. This will make sure the function is not executed more than once every 5 minutes (or whateer time interval in seconds you pass to the decorator), no matter whether it's called in that loop or elsewhere.
import time
def onceEveryXSeconds(seconds): # this creates the decorator
def wrapper(f): # decorator for given 'seconds'
f.last_execution = 0 # memorize last execution time
def decorated(*args, **kwargs): # the 'decorated' function
if f.last_execution < time.time() - seconds:
f.last_execution = time.time()
return f(*args, **kwargs)
return decorated
return wrapper
Usage:
#onceEveryXSeconds(3)
def function(foo):
print foo
while True:
print "loop"
function("Hello again")
time.sleep(1)
Output, with #onceEveryXSeconds(3)
loop
Hello again
loop
loop
loop
Hello again
loop
...
Assuming the loop takes longer than five minutes, you could use time.time() to determine when 5 minutes has been up.
import time
matches = []
done = []
starttime = time.time()
for item in matches:
dofunctioneveryloop()
done.extent(item)
if time.time() - starttime > 300:
dofunctiononce5min()
starttime = time.time()
It is not recommended that you do this way. Perhaps the best approach could be to schedule it on operation system, and it run it task periodically.
Anyway, if want to run a statement every x time, here is an example
import time
for i in range(5):
print i
time.sleep(3) # seconds
Time as parameter should be fractioned like 0.5 seconds.
Related
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. '''
...
This question already has answers here:
How to add a timeout to a function in Python
(5 answers)
Closed 1 year ago.
I have a function that I run on a number of data frames. I'd like to be able to organize this a bit better and add in a timeout statement. I'm a bit new to this...
organize data frames -
d = {}
dfs = [1,2,3]
for name in dfs:
df[name] = some_function()
And then set-up to organize these into a clean loop that checks how long the df takes to run. So it would run df_1 and df_2 because they take 5 seconds but would skip and print df_3 that it took x number of seconds.
def timeout():
# check how long df_1, df_2, df_3 takes and if takes longer than 30 seconds then print out the df name
You could use a Timer (from the threading module) but your loop must cooperate and stop then the time is expired. This could also be done by checking the elapsed time at each iteration but I believe the Timer approach would incur less overhead.
Assuming you are using an iterator for the loop, you can define a generic "timeOut" function to force it to stop after a given number of seconds:
from threading import Timer
def timeout(maxTime,iterator):
stop = False
def timedOut(): # function called when timer expires
nonlocal stop
stop = True
t = Timer(maxTime,timedOut)
t.start()
for r in iterator:
if stop: break # you could print the content of r here if needed.
yield r
t.cancel()
output:
for i in timeout(3,range(1000)):
for _ in range(10000000): pass
print(i)
1
2
3
4
5
6
7
8 # it stopped here after 3 seconds with 992 iterations to go
In your example, this could be:
d = {}
dfs = [1,2,3]
for name in timeout(5,dfs):
df[name] = some_function()
Note that this will stop the loop on dfs when the total processing time exceeds 5 seconds but it cannot interrupt what is going on inside some_funtion() if it exceeds the total time.
If you need a timeout that is not tied to a specific loop, you can create an instance of a Timer that you store in global variable or in a singleton class and check its state at appropriate places in you code:
t = Timer(25,lambda:pass) # timer will not do anything when expired
t.start() # but will no longer be alive after 25 seconds
...
# at appropriate places in your code
if not t.is_alive(): return # or break or continue ...
I have a function that runs an iterative deepening search and would like to return the value from the deepest search after a certain amount of time has passed. The code skeleton would look something like
import time
answers = []
START = time.clock()
current_depth = 1
while time.clock() - START < DESIRED_RUN_TIME:
answers.append(IDS(depth=current_depth))
current_depth += 1
return answers[-1]
The problem with this code is it will not return until after the time limit has passed. What is the best way to solve this? If I should just add time checks in the IDS function, how can I make sure to return the last value found? Any help would be greatly appreciated.
Your code should work unless IDS is blocking and takes a very long time. Then you have to wait until IDS is finished and the time limit may not be all that precise.
I'm not sure exactly what you mean by
would like to return the value from the deepest search after a certain amount of time has passed.
and
The problem with this code is it will not return until after the time limit has passed.
If you have time limits and you have update times then you can use this code as a generator.
import time
answers = []
START = time.clock()
current_depth = 1
def get_ids(update_time, limit_time):
last_update = time.clock()
while time.clock() - START < DESIRED_RUN_TIME:
answers.append(IDS(depth=current_depth))
current_depth += 1
if time.clock() - last_update < update_time:
last_update = time.clock()
yield answers[-1]
yield answers[-1]
for i in get_ids(1, 10): # get an ids every second and stop after 10 seconds
print(i)
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.
I need to execute a piece of code inside a while True loop every, let's say, 5 seconds. I know the threading.Timer(5, foo).start() will be run every 5 seconds but my foo() function depends on a variable inside my while loop.
The foo is actually run on another thread and I don't want to block the current thread just for timing's sake.
+------------------------while #main-thread---------------------------------
|
+..........foo(val)..........foo(val)...........foo(val)............foo(val)
-5s- -5s- -5s- -5s-
Something like this:
def input(self):
vals = []
while True:
# fill the vals
# run `foo(vals)` every 5 seconds
def foo(vals):
print vals
Is there any Pythonic way of doing this?
Use the sleep function:
import time
def input(self):
vals = []
while True:
# fill the vals
foo(vals)
time.sleep(5)
def foo(vals):
print vals
Note that the command will run every 5 seconds exactly only if the time needed to run it is itself negligible.