Timeout function if it takes too long to finish
Become part of the top 3% of the developers by applying to Toptal https://topt.al/25cXVn
--
Music by Eric Matyas
https://www.soundimage.org
Track title: Popsicle Puzzles
--
Chapters
00:00 Question
00:54 Accepted answer (Score 274)
02:20 Answer 2 (Score 193)
02:57 Thank you
--
Full question
https://stackoverflow.com/questions/2281...
Accepted answer links:
[signal]: http://docs.python.org/library/signal#ex...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python
#avk47
--
Music by Eric Matyas
https://www.soundimage.org
Track title: Popsicle Puzzles
--
Chapters
00:00 Question
00:54 Accepted answer (Score 274)
02:20 Answer 2 (Score 193)
02:57 Thank you
--
Full question
https://stackoverflow.com/questions/2281...
Accepted answer links:
[signal]: http://docs.python.org/library/signal#ex...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python
#avk47
ACCEPTED ANSWER
Score 286
The process for timing out an operations is described in the documentation for signal.
The basic idea is to use signal handlers to set an alarm for some time interval and raise an exception once that timer expires.
Note that this will only work on UNIX.
Here's an implementation that creates a decorator (save the following code as timeout.py).
import errno
import os
import signal
import functools
class TimeoutError(Exception):
pass
def timeout(seconds=10, error_message=os.strerror(errno.ETIME)):
def decorator(func):
def _handle_timeout(signum, frame):
raise TimeoutError(error_message)
@functools.wraps(func)
def wrapper(*args, **kwargs):
signal.signal(signal.SIGALRM, _handle_timeout)
signal.alarm(seconds)
try:
result = func(*args, **kwargs)
finally:
signal.alarm(0)
return result
return wrapper
return decorator
This creates a decorator called @timeout that can be applied to any long running functions.
So, in your application code, you can use the decorator like so:
from timeout import timeout
# Timeout a long running function with the default expiry of 10 seconds.
@timeout
def long_running_function1():
...
# Timeout after 5 seconds
@timeout(5)
def long_running_function2():
...
# Timeout after 30 seconds, with the error "Connection timed out"
@timeout(30, os.strerror(errno.ETIMEDOUT))
def long_running_function3():
...
ANSWER 2
Score 203
I rewrote David's answer using the with statement, it allows you do do this:
with timeout(seconds=3):
time.sleep(4)
Which will raise a TimeoutError.
The code is still using signal and thus UNIX only:
import signal
class timeout:
def __init__(self, seconds=1, error_message='Timeout'):
self.seconds = seconds
self.error_message = error_message
def handle_timeout(self, signum, frame):
raise TimeoutError(self.error_message)
def __enter__(self):
signal.signal(signal.SIGALRM, self.handle_timeout)
signal.alarm(self.seconds)
def __exit__(self, type, value, traceback):
signal.alarm(0)