这是
signal您链接的装饰器使用的模块计时功能的限制。这是文档的相关部分(我重点强调):
signal.alarm(time)如果时间不为零,则此函数要求
SIGALRM以time秒为单位将信号发送到进程。
任何先前计划的警报都会被取消(任何时候都只能计划一个警报)。
然后,返回值是在传递任何先前设置的警报之前的秒数。如果time为零,则不计划任何警报,并且任何计划的警报都将被取消。如果返回值为零,则当前未计划任何警报。(请参见Unix手册页alarm(2)。)可用性:Unix。
因此,您所看到的是,在
nested_func调用your时,它的计时器取消了外部函数的计时器。
您可以更新装饰器,以注意
alarm呼叫的返回值(这是上一个警报(如果有)到期之前的时间)。正确获取细节有点复杂,因为内部计时器需要跟踪其功能运行了多长时间,因此它可以修改前一个计时器上的剩余时间。这是装饰器的一个未经测试的版本,我认为它基本上是正确的(但是我不完全确定它对于所有异常情况都可以正常工作):
import timeimport signalclass TimeoutError(Exception): def __init__(self, value = "Timed Out"): self.value = value def __str__(self): return repr(self.value)def timeout(seconds_before_timeout): def decorate(f): def handler(signum, frame): raise TimeoutError() def new_f(*args, **kwargs): old = signal.signal(signal.SIGALRM, handler) old_time_left = signal.alarm(seconds_before_timeout) if 0 < old_time_left < second_before_timeout: # never lengthen existing timer signal.alarm(old_time_left) start_time = time.time() try: result = f(*args, **kwargs) finally: if old_time_left > 0: # deduct f's run time from the saved timer old_time_left -= time.time() - start_time signal.signal(signal.SIGALRM, old) signal.alarm(old_time_left) return result new_f.func_name = f.func_name return new_f return decorate



