Best way to implment timeout for a while loop - python

I have a while loop
while somecondition:
dostuff
(Sorry. It is hard to give an executable example as this is part of a larger project).
Most of the time the condition is met after a short while and the loop expires. But sometimes the condition will never be met. How can I best catch such cases? Is a timer the best option? How can I implement it best?

You can use a timeout using SIGALRM. Here's a little program that demonstrates it.
import sys
import time
import signal
class TimeoutError(Exception):
pass
def _sig_alarm(sig, tb):
raise TimeoutError("timeout")
def main(argv):
timeout = 7
signal.signal(signal.SIGALRM, _sig_alarm)
try:
signal.alarm(timeout)
while True:
print("sleeping...")
time.sleep(1)
except TimeoutError:
pass
print("Out of loop.")
main(sys.argv)
This sets up a signal handler that simply raises a custom exception (but you can use any), and then catches it.

wait for an hour example
from datetime import timedelta
delete_TO = 1
wait_until = datetime.now() + timedelta(hours=delete_TO)
break_loop = False
while not break_loop:
do-your loop-stuff
if wait_until < datetime.now() or somecondition:
break_loop = True
(edited: wait_until must be smaller than datetime.now() )

The correct answer is
from datetime import timedelta
delete_TO = 1
wait_until = datetime.now() + timedelta(hours=delete_TO)
break_loop = False
while not break_loop:
do-your loop-stuff
if wait_until < datetime.now() or somecondition:
break_loop = True
This code is copy pasted from #ohad_the_lad (https://stackoverflow.com/users/2468201/ohad-the-lad) answer, but it fixes the unintentional bug where the loop exits if wait_until is greater than datetime.now() which will always happen.

How about writing a for loop? Or you can implement something like timer=0 an increment it every time you pass the loop. For example if you wanted to break after 100 iterations you could write an if statement. If timer == 100 then break.

Related

Let Python keep loop statement running and check the condition every 3 seconds

I want to keep the loop conditional statement running, but do not always check the conditions.
For example, if the condition is true, then in the next 3 seconds, the loop's conditional statement will run, and then check the condition after the 3rd second, then repeat this process.
I don't want to wait or sleep for three seconds, I want my loop to do work for three seconds. And then check if it should continue for another three as mentioned by #RemcoGerlich
while if_active() == True: #check the condition every 3 seconds`
try: # it will keep running in 3 seconds if if_active() is true
with open(masterpath, 'r') as f:
s = f.read()
exec(s)
Here's a fun and async way. Just for fun, with a demo for activateing
import signal, os
import time
def handler(signum, frame):
for i in range(3):
print("foo bar")
time.sleep(0.1)
signal.alarm(3)
# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(3)
while True:
try:
active = not active
if not active:
signal.alarm(0)
time.sleep(60)
except KeyboardInterrupt as interrupt:
# demonstrating activate, with ctrl+c
signal.alarm(3)
You can track when the last time was that you did the check, and only re-do the check if three seconds have passed.
from datetime import datetime, timedelta
INTERVAL = timedelta(minutes=3)
last_checked = datetime.now() - INTERVAL
while True:
now = datetime.now()
if last_checked <= (now - INTERVAL):
if not if_active():
break
last_checked = now
# do your thing here
pass
This could use some refactoring but the idea should work.
You can use a command like sleep to avoid running continuously. You can see a more explained answer in this thread: How can I make a time delay in Python?

Python: Terminate Loop Using Timer

I'm quite new on python and working on a school project with this logic: Users have to answer a series of questions as fast as they can, within the given time.
For instance, the time allotted is 30 seconds, I wood loop through a dictionary of questions and get the answer. On timeout, the loop will start, even if the script is still waiting for an input.
def start_test():
for item on questions:
print(item)
answers.append(input(' : '))
I've tried using multiprocessing and multithreading, but I found out that stdin doesn't work subprocesses.
I'm looking for something like:
while duration > 0:
start_test()
def countdown():
global duration
while duration > 0:
duration -= 1
time.sleep(1)
# something lime start_test().stop()
But I can't figure out how to run the countdown function in parallel with the start_test function.
Any ideas?
So as far as I know the input is accessible via main thread only. I might be wrong.
However if that is the case, you need a non-blocking input.
Check this blog. The answer below is based on that.
Note: This is a really quick and dirty solution.
I have checked this on Linux.
If it doesn't work on Windows try this
link for further reference.
import _thread
import sys
import select
import time
def start_test():
questions = ['1','2','3']
answers = []
for item in questions:
print(item)
# Input in a non-blocking way
loop_flag = True
while loop_flag:
# Read documenation and examples on select
ready = select.select([sys.stdin], [], [], 0)[0]
if not ready:
# Check if timer has expired
if timeout:
return answers
else:
for file in ready:
line = file.readline()
if not line: # EOF, input is closed
loop_flag = False
break
elif line.rstrip():
# We have some input
answers.append(line)
# So as to get out of while
loop_flag = False
# Breaking out of for
break
return answers
def countdown():
global timeout
time.sleep(30)
timeout = True
# Global Timeout Flag
timeout = False
timer = _thread.start_new_thread(countdown, ())
answers = start_test()
print(answers)

Use a variable, that is in a while loop, in an if statement python

import datetime
time = datetime.datetime.now()
hm = 0
def function():
while True:
hm = (time.hour, time.minute)
break
if hm == (6,30):
"stuff"
function()
else:
"stuff"
My goal is to get the time and then do something once it reaches a certain time. My editor gives me an error saying the code is unreachable. I don't know what to do since I cannot return a variable in a while loop. Thanks.
You don't have any break statement in the Loop. The if/else is outside of the loop's scope. You need to indent it, and add some break statements.
I'd skip the while loop and go with an approach more like this (if you don't want to use a library):
import datetime
import time
start_time = datetime.datetime.now()
end_time = start_time.replace(hour=18, minute=30, second=0, microsecond=0)
delta = end_time - start_time
time.sleep(delta.total_seconds())
# do stuff

How to end program running after given time in Python

I'd like my Python program to run an algorithm for a given number of seconds and then to print the best result so far and to end.
What is the best way to do so?
I tried the following but it did not work(the program kept running after the printing):
def printBestResult(self):
print(self.bestResult)
sys.exit()
def findBestResult(self,time):
self.t = threading.Timer(time, self.printBestResult)
self.t.start()
while(1):
# find best result
Untested code, but something like this?
import time
threshold = 60
start = time.time()
best_run = threshold
while time.time()-start < threshold:
run_start = time.time()
doSomething()
run_time = time.time() - start
if run_time < best_run:
best_run = run_time
On unix, you can use signals -- This code times out after 1 second and counts how many times it iterates through the while loop in that time:
import signal
import sys
def handle_alarm(args):
print args.best_val
sys.exit()
class Foo(object):
pass
self=Foo() #some mutable object to mess with in the loop
self.best_val=0
signal.signal(signal.SIGALRM,lambda *args: handle_alarm(self))
signal.alarm(1) #timeout after 1 second
while True:
self.best_val+=1 # do something to mutate "self" here.
Or, you could easily have your alarm_handler raise an exception which you then catch outside the while loop, printing your best result.
If you want to do this with threads, a good way is to use an Event. Note that signal.alarm won't work in Windows, so I think threading is your best bet unless in that case.
import threading
import time
import random
class StochasticSearch(object):
def __init__(self):
self.halt_event = threading.Event()
def find_best_result(self, duration):
halt_thread = threading.Timer(duration, self.halt_event.set)
halt_thread.start()
best_result = 0
while not self.halt_event.is_set():
result = self.search()
best_result = result if result > best_result else best_result
time.sleep(0.5)
return best_result
def search(self):
val = random.randrange(0, 10000)
print 'searching for something; found {}'.format(val)
return val
print StochasticSearch().find_best_result(3)
You need an exit condition, or the program will run forever (or until it runs out of memory). Add one yourself.

kill a function after a certain time in windows

I've read a lot of posts about using threads, subprocesses, etc.. A lot of it seems over complicated for what I'm trying to do...
All I want to do is stop executing a function after X amount of time has elapsed.
def big_loop(bob):
x = bob
start = time.time()
while True:
print time.time()-start
This function is an endless loop that never throws any errors or exceptions, period.
I"m not sure the difference between "commands, shells, subprocesses, threads, etc.." and this function, which is why I'm having trouble manipulating subprocesses.
I found this code here, and tried it but as you can see it keeps printing after 10 seconds have elapsed:
import time
import threading
import subprocess as sub
import time
class RunCmd(threading.Thread):
def __init__(self, cmd, timeout):
threading.Thread.__init__(self)
self.cmd = cmd
self.timeout = timeout
def run(self):
self.p = sub.Popen(self.cmd)
self.p.wait()
def Run(self):
self.start()
self.join(self.timeout)
if self.is_alive():
self.p.terminate()
self.join()
def big_loop(bob):
x = bob
start = time.time()
while True:
print time.time()-start
RunCmd(big_loop('jimijojo'), 10).Run() #supposed to quit after 10 seconds, but doesn't
x = raw_input('DONEEEEEEEEEEEE')
What's a simple way this function can be killed. As you can see in my attempt above, it doesn't terminate after 20 seconds and just keeps on going...
***OH also, I've read about using signal, but I"m on windows so I can't use the alarm feature.. (python 2.7)
**assume the "infinitely running function" can't be manipulated or changed to be non-infinite, if I could change the function, well I'd just change it to be non infinite wouldn't I?
Here are some similar questions, which I haven't able to port over their code to work with my simple function:
Perhaps you can?
Python: kill or terminate subprocess when timeout
signal.alarm replacement in Windows [Python]
Ok I tried an answer I received, it works.. but how can I use it if I remove the if __name__ == "__main__": statement? When I remove this statement, the loop never ends as it did before..
import multiprocessing
import Queue
import time
def infinite_loop_function(bob):
var = bob
start = time.time()
while True:
time.sleep(1)
print time.time()-start
print 'this statement will never print'
def wrapper(queue, bob):
result = infinite_loop_function(bob)
queue.put(result)
queue.close()
#if __name__ == "__main__":
queue = multiprocessing.Queue(1) # Maximum size is 1
proc = multiprocessing.Process(target=wrapper, args=(queue, 'var'))
proc.start()
# Wait for TIMEOUT seconds
try:
timeout = 10
result = queue.get(True, timeout)
except Queue.Empty:
# Deal with lack of data somehow
result = None
finally:
proc.terminate()
print 'running other code, now that that infinite loop has been defeated!'
print 'bla bla bla'
x = raw_input('done')
Use the building blocks in the multiprocessing module:
import multiprocessing
import Queue
TIMEOUT = 5
def big_loop(bob):
import time
time.sleep(4)
return bob*2
def wrapper(queue, bob):
result = big_loop(bob)
queue.put(result)
queue.close()
def run_loop_with_timeout():
bob = 21 # Whatever sensible value you need
queue = multiprocessing.Queue(1) # Maximum size is 1
proc = multiprocessing.Process(target=wrapper, args=(queue, bob))
proc.start()
# Wait for TIMEOUT seconds
try:
result = queue.get(True, TIMEOUT)
except Queue.Empty:
# Deal with lack of data somehow
result = None
finally:
proc.terminate()
# Process data here, not in try block above, otherwise your process keeps running
print result
if __name__ == "__main__":
run_loop_with_timeout()
You could also accomplish this with a Pipe/Connection pair, but I'm not familiar with their API. Change the sleep time or TIMEOUT to check the behaviour for either case.
There is no straightforward way to kill a function after a certain amount of time without running the function in a separate process. A better approach would probably be to rewrite the function so that it returns after a specified time:
import time
def big_loop(bob, timeout):
x = bob
start = time.time()
end = start + timeout
while time.time() < end:
print time.time() - start
# Do more stuff here as needed
Can't you just return from the loop?
start = time.time()
endt = start + 30
while True:
now = time.time()
if now > endt:
return
else:
print end - start
import os,signal,time
cpid = os.fork()
if cpid == 0:
while True:
# do stuff
else:
time.sleep(10)
os.kill(cpid, signal.SIGKILL)
You can also check in the loop of a thread for an event, which is more portable and flexible as it allows other reactions than brute killing. However, this approach fails if # do stuff can take time (or even wait forever on some event).

Categories