這是模塊的定時功能的限制,您鏈接的裝飾器使用該功能。下面是有關piece of the documentation(由我加的):
signal.alarm(time)
如果時間爲非零,一個SIGALRM
信號time
秒被髮送到處理該功能的請求。 任何先前預定的警報都會取消(只能在任何時間安排一個警報)。然後返回的值是任何先前設置的警報傳遞之前的秒數。如果time
爲零,則不安排警報,並且任何安排的警報都將被取消。如果返回值爲零,則當前不安排警報。 (請參閱Unix手冊頁警報(2)。)可用性:Unix。
所以,你看到的是當你的nested_func
被調用時,它的計時器取消了外部函數的計時器。
您可以更新修飾器,以關注alarm
調用的返回值(這將是上次警報(如果有)到期之前的時間)。因爲內部定時器需要跟蹤它的功能運行時間,所以它可以修改前一個定時器的剩餘時間,這對於獲取細節是件很複雜的事情。這裏的裝飾的未經測試的版本,我認爲得到它基本上是正確的(但我不能完全肯定它可以正確處理所有的異常情況):
import time
import signal
class 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
你是哪個異常情況下不知道? – JavaSa
我想這不是例外情況,因爲'finally'塊能夠很好地清理事件,但是之前設置的警報的情況可能不會得到最好的處理。我也無法測試代碼,因爲'signal.alarm'在我的操作系統上不可用。 – Blckknght
我想我們還需要添加一個檢查,old_time_left - = time.time() - start_time> 0,它可以是負數,我認爲 – JavaSa