中断功能并在一定时间后继续 - Python
Break function and move on after certain time has elapsed - Python
我一直在尝试创建一个超时,告诉我的一段代码在一定时间内没有达到结果时继续前进。
我测试了此处发布的主要答案中的代码:break the function after certain time,它运行良好,但是当我用我的代码实现它时它不起作用。
无论 'Try' 中的代码块执行多长时间,都不会触发 TimeoutException。此代码块中的计时器始终打印出大于 5 秒,即使如果代码花费的时间超过 signal.alarm(5).signal.alarm(5).
允许的 5 秒,甚至不应调用打印操作。
您能想到没有触发 TimeoutException 的任何原因吗?我该如何解决?
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 的 zen 中也被列为如此)。
如果您有权访问该函数的源代码,请寻找 try/excecpt 块并包括打印以检查它,并捕获特定的异常而不是裸露的异常。
如果您无法深入研究该代码 - 您可以一次性尝试将 TimeoutException
的基数更改为 BaseException
(代替 Exception
)。
在任何情况下,您的方法似乎都不是解决手头问题的最佳方法 - 信号确实不能与很多类型的代码一起使用,包括多线程或其他事件 -基于循环的代码。
此外,即使您的处理程序在正确的时间正确地引发了 Python 异常,如果您的 long-运行ning 函数是本机代码,Python 本身也不会处理异常(并因此将执行切换到 except
块)直到本机代码函数 returns。我排除了这是你的(唯一)问题,因为在那种情况下,以下打印语句不会 运行 - 它会花费超过 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)
我一直在尝试创建一个超时,告诉我的一段代码在一定时间内没有达到结果时继续前进。
我测试了此处发布的主要答案中的代码:break the function after certain time,它运行良好,但是当我用我的代码实现它时它不起作用。
无论 'Try' 中的代码块执行多长时间,都不会触发 TimeoutException。此代码块中的计时器始终打印出大于 5 秒,即使如果代码花费的时间超过 signal.alarm(5).signal.alarm(5).
允许的 5 秒,甚至不应调用打印操作。您能想到没有触发 TimeoutException 的任何原因吗?我该如何解决?
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 的 zen 中也被列为如此)。
如果您有权访问该函数的源代码,请寻找 try/excecpt 块并包括打印以检查它,并捕获特定的异常而不是裸露的异常。
如果您无法深入研究该代码 - 您可以一次性尝试将 TimeoutException
的基数更改为 BaseException
(代替 Exception
)。
在任何情况下,您的方法似乎都不是解决手头问题的最佳方法 - 信号确实不能与很多类型的代码一起使用,包括多线程或其他事件 -基于循环的代码。
此外,即使您的处理程序在正确的时间正确地引发了 Python 异常,如果您的 long-运行ning 函数是本机代码,Python 本身也不会处理异常(并因此将执行切换到 except
块)直到本机代码函数 returns。我排除了这是你的(唯一)问题,因为在那种情况下,以下打印语句不会 运行 - 它会花费超过 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)