is there a way to time limit the oparations in python, eg:
try:
cmds.file( file, o=1, pmt=0 )
except:
print "Sorry, run out of time"
pass
If you're on Mac or a Unix-based system, you can use signal.SIGALRM to forcibly time out functions that take too long, so your code would look like:
import signal
class TimeoutException(Exception): # custom exception
pass
def timeout_handler(signum, frame): # raises exception when signal sent
raise TimeoutException
# Makes it so that when SIGALRM signal sent, it calls the function timeout_handler, which raises your exception
signal.signal(signal.SIGALRM, timeout_handler)
# Start the timer. Once 5 seconds are over, a SIGALRM signal is sent.
signal.alarm(5)
try:
cmds.file( file, o=1, pmt=0 )
except TimeoutException:
print "Sorry, run out of time" # you don't need pass because that's in the exception definition
Basically, you're creating a custom exception that's raised when the after the time limit is up (i.e., the SIGALRM is sent). You can of course tweak the time limit.
Related
I'm trying to make alarm work over and over again.
My handler is
def handler_SIGALRM(signum, frame):
print "waiting"
signal.alarm(2)
The alarm work only once, even though every time I set it again.
In my code I also use sigchld and sys.exit after the child working.
I'm running it with cygwin.
EDIT:
I need to write a code that will print "waiting" every second, with sigalarm and not loops
I'm an idiot, I edited the wrong code
You put your signal.alarm(2) in a wrong place. See my example below.
import time
import signal
class TimeoutException (Exception):
pass
def signalHandler (signum, frame):
raise TimeoutException ()
timeout_duration = 5
signal.signal (signal.SIGALRM, signalHandler)
for i in range (5):
signal.alarm (timeout_duration)
try:
"""Do something that has a possibility of taking a lot of time
and exceed the timeout_duration"""
time.sleep (20)
except TimeoutException as exc:
print "Notify your program that the timeout_duration has passed"
finally:
#Clean out the alarm
signal.alarm (0)
Let's say we have a code sample as below which prints hello, world after 5 seconds. I want a way to check if Timer thread took more than 5 seconds then terminate the thread.
from threading import Timer
from time import sleep
def hello():
sleep(50)
print "hello, world"
t = Timer(5, hello)
# after 5 seconds, "hello, world" will be printed
t.start()
In the above code block hello will take more than 5 seconds to process.
consider hello function, a call to outside server that returns no response and even no exception for timeout or anything! I wanted to simulate the issue with sleep function.
You can use signal and call its alarm method. An exception (which you can handle) will be raised after the timeout time has passed. See an (incomplete) example below.
import signal
class TimeoutException (Exception):
pass
def signalHandler (signum, frame):
raise TimeoutException ()
timeout_duration = 5
signal.signal (signal.SIGALRM, signalHandler)
signal.alarm (timeout_duration)
try:
"""Do something that has a possibility of taking a lot of time
and exceed the timeout_duration"""
except TimeoutException as exc:
"Notify your program that the timeout_duration has passed"
finally:
#Clean out the alarm
signal.alarm (0)
You can read more about Python's signal here https://docs.python.org/2/library/signal.html.
I'm writing a small, single function that is designed to request user input with a time delay. When the time delay runs out, the function should return None instead of a user's response and then should continue with the rest of the script.
In the current implementation, the user input works and the timeout works, with the timeout message printed by a signal handler function which is defined within the function (I'm aiming to have this outer function fairly self-contained). However, processing then halts (rather than exiting the while loop defined in the main function) and I'm not sure why.
How can I get processing to continue? Am I misusing signal in some way? Could a lambda be used in place of an explicitly-defined function for the handler function?
#!/usr/bin/env python
from __future__ import print_function
import signal
import propyte
def main():
response = "yes"
while response is not None:
response = get_input_nonblocking(
prompt = "ohai? ",
timeout = 5
)
print("start non-response procedures")
# do things
def get_input_nonblocking(
prompt = "",
timeout = 5,
message_timeout = "prompt timeout"
):
def timeout_manager(signum, frame):
print(message_timeout)
#signal.signal(signal.SIGALRM, lambda: print(message_timeout))
signal.signal(signal.SIGALRM, timeout_manager)
signal.alarm(timeout)
try:
response = propyte.get_input(prompt)
return response
except:
return None
if __name__ == '__main__':
main()
What you've got is almost there, but you need to raise an exception inside your signal handler. raw_input will block until something happens, either input or an exception. If you raise an exception in the signal handler, that will then interrupt raw_input and execution will fall into the except in your get_input_non_blocking function. Here's a toy example.
import signal
def timeout(signum, frame):
raise IOError("bye!")
signal.signal(signal.SIGALRM, timeout)
def input():
try:
print("omgplz: ")
return raw_input()
except IOError:
return None
signal.alarm(5)
txt = input()
signal.alarm(0)
print(txt)
There's some more discussion and an alternative approach using select in this answer here: Keyboard input with timeout in Python
Hope that helps!
Hi I embeded a time constraint in to my python code which is running a fortran code with a function. However I realized that the function that puts a time constraint on the other function doesn't terminates the code, just leaves it in background and skips it instead. What I want to do is terminate the code, when it exceed the constrained time. Here is the code that I'm using to constrain time which is taken from here.
def timeout(func, args=(), kwargs={}, timeout_duration=15, default=1):
import signal
class TimeoutError(Exception):
pass
def handler(signum, frame):
raise TimeoutError()
# set the timeout handler
signal.signal(signal.SIGALRM, handler)
signal.alarm(timeout_duration)
try:
result = func(*args, **kwargs)
except TimeoutError as exc:
result = default
finally:
signal.alarm(0)
return result
I looked up popen.terminate(), sys.exit() and atexit.register() but couldn't figure out how it will work with this piece of code which I tried to add in part below that I showed in comment.
...
result = func(*args, **kwargs)
except TimeoutError as exc:
result = default
#add the terminator
finally:
...
NOTE: Function is inside a for loop chain so I dont want to kill whole python session but just want to kill the program that this function runs which is a fortran code and skip to the other element in the for loop chain.
Part below added after some comments and answers:
I tried to add SIGTERM with popen.terminate() however it terminated all python session which I just want to terminate current running session and skip to the other elements in the for loop. what I did is as follows:
...
signal.signal(signal.SIGTERM, handler)
signal.alarm(timeout_duration)
try:
result = func(*args, **kwargs)
except TimeoutError as exc:
result = default
popen.terminate()
...
You cannot expect the signal handler raising an Exception to get propagated through the call stack, it's invoked in a different context.
popen.terminate() will generate SIGTERM on posix systems so you should have a signal handler for SIGTERM and not SIGALRM.
Instead of raising an exception in your signal handler, you should set some variable that you periodically check in order to halt activity.
Alternatively if you don't have a signal handler for SIGTERM the default handler will probably generate a KeyboardInterrupt exception.
I am using python 2.7
I want to create a wrapper function around fcntl.flock() that will timeout after a set interval:
wrapper_function(timeout):
I've tried calling on another thread and using thread.join(timeout) but it seems that fcntl.flock() continues blocking:
def GetLock(self, timeout):
"""Returns true if lock is aquired, false if lock is already in use"""
self.__lock_file = open('proc_lock', 'w')
def GetLockOrTimeOut():
print 'ProcessLock: Acquiring Lock'
fcntl.flock(self.__lock_file.fileno(), fcntl.LOCK_EX)
print 'ProcessLock: Lock Acquired'
thread = threading.Thread(target=GetLockOrTimeOut)
thread.start()
thread.join(timeout)
if thread.isAlive():
print 'GetLock timed out'
return False
else:
return True
I've looked into solutions for terminating threads, the most popular solution seems to be sub-classing threading.thread and adding a feature to raise an exception in the thread. However, I came across a link that says this method will not work with native calls, which I am pretty sure fcntl.flock() is calling a native function. Suggestions?
Context: I am using a file-lock to create a single instance application but I don't want a second instance of the application to sit around and hang until the first instance terminates.
Timeouts for system calls are done with signals. Most blocking system calls return with EINTR when a signal happens, so you can use alarm to implement timeouts.
Here's a context manager that works with most system calls, causing IOError to be raised from a blocking system call if it takes too long.
import signal, errno
from contextlib import contextmanager
import fcntl
#contextmanager
def timeout(seconds):
def timeout_handler(signum, frame):
pass
original_handler = signal.signal(signal.SIGALRM, timeout_handler)
try:
signal.alarm(seconds)
yield
finally:
signal.alarm(0)
signal.signal(signal.SIGALRM, original_handler)
with timeout(1):
f = open("test.lck", "w")
try:
fcntl.flock(f.fileno(), fcntl.LOCK_EX)
except IOError, e:
if e.errno != errno.EINTR:
raise e
print "Lock timed out"
I'm sure there are several ways, but how about using a non-blocking lock? After some n attempts, give up and exit?
To use non-blocking lock, include the fcntl.LOCK_NB flag, as in:
fcntl.flock(self.__lock_file.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
For Python 3.5+, Glenn Maynard's solution no longer works because of PEP-475. This is a modified version:
import signal, errno
from contextlib import contextmanager
import fcntl
#contextmanager
def timeout(seconds):
def timeout_handler(signum, frame):
# Now that flock retries automatically when interrupted, we need
# an exception to stop it
# This exception will propagate on the main thread, make sure you're calling flock there
raise InterruptedError
original_handler = signal.signal(signal.SIGALRM, timeout_handler)
try:
signal.alarm(seconds)
yield
finally:
signal.alarm(0)
signal.signal(signal.SIGALRM, original_handler)
with timeout(1):
f = open("test.lck", "w")
try:
fcntl.flock(f.fileno(), fcntl.LOCK_EX)
except InterruptedError:
# Catch the exception raised by the handler
# If we weren't raising an exception, flock would automatically retry on signals
print("Lock timed out")
I'm a fan of shelling out to flock here, since attempting to do a blocking lock with a timeout requires changes to global state, which makes it harder to reason about your program, especially if threading is involved.
You could fork off a subprocess and implement the alarm as above, or you could just exec http://man7.org/linux/man-pages/man1/flock.1.html
import subprocess
def flock_with_timeout(fd, timeout, shared=True):
rc = subprocess.call(['flock', '--shared' if shared else '--exclusive', '--timeout', str(timeout), str(fd)])
if rc != 0:
raise Exception('Failed to take lock')
If you have a new enough version of flock you can use -E to specify a different exit code for the command otherwise succeeding, but failed to take the lock after a timeout, so you can know whether the command failed for some other reason instead.
As a complement to #Richard Maw answer above https://stackoverflow.com/a/32580233/17454091 (Don't have enough reputation to post a comment).
In Python 3.2 and newer, for fds to be available in sub-processes one must also provide pass_fds argument.
Complete solution ends up as:
import subprocess
def flock_with_timeout(fd, timeout, shared=True):
rc = subprocess.call(['flock',
'--shared' if shared else '--exclusive',
'--timeout', str(timeout),
str(fd)],
pass_fds=[fd])
if rc != 0:
raise Exception('Failed to take lock')