def with_timeout(timeout=0, exception=TTimeout):
def async_raise(target_tid, exc):
"""Raises an asynchronous exception in another thread.
Read http://docs.python.org/c-api/init.html#PyThreadState_SetAsyncExc
for further enlightenments.
coped from stopit
:param target_tid: target thread identifier
:param exc: Exception class to be raised in that thread
"""
ret = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(target_tid),
ctypes.py_object(exc))
if ret == 0:
raise ValueError("Invalid thread ID {}".format(target_tid))
elif ret > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(target_tid), None)
raise SystemError("PyThreadState_SetAsyncExc failed")
class MyTimer(object):
def __init__(self, time_out=0, exc=TTimeout):
"""
:param time_out: time out seconds
:param exc: when time out occur raise exc out
"""
self.target_tid = threading.current_thread().ident
self.timer = None # PEP8
self.time_out = time_out
self.exception = exc
def __shut_down(self):
async_raise(self.target_tid, self.exception)
def __start(self):
self.timer = threading.Timer(timeout, self.__shut_down)
timer.start()
def __enter__(self):
self.__start()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.timer.cancel()
return False
def deco(func):
@wraps(func)
def wraper(*args, **kwargs):
"""
using __enter__ and __exit__ to ensure when the thread async_raised,
it is aliving
it will raise any exception from func
"""
result = None
with MyTimer(timeout, exception) as mytimer:
result = func(*args, **kwargs)
return result
return wraper
return deco
用法:
@with_timeout(2)
def loop_test(t=2):
last_time = time.time()
while True:
if time.time() - last_time > t:
break
time.sleep(t * 0.1 / 10.0)
核心方法抄的,不过这里面对try expect finally 和__enter__,__exit__有了深度认识,很开心