I am trying to implement timeout for a particular function. I have checked many of the questions in SE and couldn't find any solution which fits my problem, because:
I am having a already designed custom module (say MyModule
) developed for particular tasks, and there are functions defined in it. One of the function (say MyFunc
) has a tendency to run forever because of external factors, and I just don't want the python script to hang.
I am planning to add a timeout feature, as said below pseudocode:
import MyModule
set_timeout(T)
MyResult=MyModule.MyFunc()
#Come to this part of script after execution of MyFunc() or after T seconds (the latter on priority)
if Timeout occurred:
print 'MyFunc did not execute completely'
else:
print 'MyFunc completed'
But I am not sure which module can be used to achieve this on python. Note that I am a newbie, and all the scripts I have written are directly based on SE Answers or Python Documentation.
Timeout is very useful when you want to limit the max time for calling a function or running a command.
Then it's as simple as this to timeout a test or any function you like: @timeout(5.0) # if execution takes longer than 5 seconds, raise a TimeoutError def test_base_regression(self): ... Be careful since this does not terminate the function after timeout is reached!
I think a good way to approach this is to create a decorator and use the Thread.join(timeout=seconds)
method. Bear in mind that there's no good way to kill the thread, so it will continue to run in the background, more or less, as long as your program is running.
First, create a decorator like this:
from threading import Thread
import functools
def timeout(timeout):
def deco(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
res = [Exception('function [%s] timeout [%s seconds] exceeded!' % (func.__name__, timeout))]
def newFunc():
try:
res[0] = func(*args, **kwargs)
except Exception as e:
res[0] = e
t = Thread(target=newFunc)
t.daemon = True
try:
t.start()
t.join(timeout)
except Exception as je:
print ('error starting thread')
raise je
ret = res[0]
if isinstance(ret, BaseException):
raise ret
return ret
return wrapper
return deco
Then, do something like this:
func = timeout(timeout=16)(MyModule.MyFunc)
try:
func()
except:
pass #handle errors here
You can use this decorator anywhere you need with something like:
@timeout(60)
def f():
...
@acushner's answer adapted for python 3.5:
from threading import Thread
import functools
def timeout(seconds_before_timeout):
def deco(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
res = [Exception('function [%s] timeout [%s seconds] exceeded!' % (func.__name__, seconds_before_timeout))]
def newFunc():
try:
res[0] = func(*args, **kwargs)
except Exception as e:
res[0] = e
t = Thread(target=newFunc)
t.daemon = True
try:
t.start()
t.join(seconds_before_timeout)
except Exception as e:
print('error starting thread')
raise e
ret = res[0]
if isinstance(ret, BaseException):
raise ret
return ret
return wrapper
return deco
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With