我一直在尝试创建一个超时,如果代码的一部分在一定时间内没有达到结果,它会告诉我的代码的一部分继续前进。
我测试了此处发布的主要答案中的代码:在一定时间后破坏函数,它运行良好,但是当我使用代码实现它时,它不起作用。
无论"尝试"中的代码块执行需要多长时间,都不会触发超时异常。此代码块中的计时器始终打印为大于 5 秒,即使如果代码花费的时间超过 signal.alarm(5) 允许的 5 秒,甚至不应调用打印操作。
你能想到没有触发超时异常的任何原因以及我该如何解决它吗?
import signal
import time
def evaluateList(dataDictionaryList):
newDataDict = []
count = 0
class TimeoutException(Exception):
pass
def timeout_handler(signum, frame):
raise TimeoutException
signal.signal(signal.SIGALRM, timeout_handler)
for dataDictionary in dataDictionaryList:
signal.alarm(5)
try:
startTime = time.time()
newDataDict.append(functionThatMightHang(dataDictionary))
print(count + 1, ' Time to evaluate: ', time.time() - startTime)
count+=1
except TimeoutException:
print('took too long')
continue
else:
signal.alarm(0)
return newDataDict
它确实应该有效 - 除非functionThatMightHang
内部的某些代码块本身捕获并吞噬了您的TimeoutException。 如果有一个 try/except 块捕获其中的裸Exception
,并且只是忽略它并继续计算,就会发生这种事情。 (这是一个糟糕的编程实践,甚至在Python的禅宗中也是如此)。
如果您有权访问该函数源代码,请搜索 try/excecpt 块并包含打印以检查它,并捕获特定异常而不是裸露的例外。
如果你不能深入研究该代码 - 你可以尝试将TimeoutException
的基础更改为BaseException
(代替Exception
)。
无论如何,你似乎不是解决你手头问题的最佳方法 - 信号真的不适合很多类型的代码,包括多线程或其他基于事件循环的代码。
此外,即使你的处理程序在正确的时间正确地引发了 Python 异常,如果你长时间运行的函数是本机代码,Python 本身也不会处理异常(从而将执行切换到except
块),直到本机代码函数返回。我排除了这是您的(唯一)问题,因为在这种情况下,以下 print-语句将无法运行 - 这将花费超过 5 秒的时间,并且它们执行except
块。
真正的修复
你可能想尝试使用 Python 的 concurrent.future 模块来运行你的长期函数。通过这种方式,你可以在另一个线程中以或多或少透明的方式运行你的长期函数(甚至在另一个进程中,它将利用多个内核),并为执行指定一个超时参数 - Python 的 concurrent.future 机器将自行处理停止计算。
这个例子适用于交互式解释器,并引发TimeoutError(concurrent.futures使用的解释器,而不是自定义解释器):
from concurrent.futures import ThreadPoolExecutor
import time
def long():
time.sleep(3)
p = ThreadPoolExecutor(1)
f = p.submit(long); f.result(timeout=1)