Python 超时功能,如果完成时间过长
我有一个shell脚本,它循环遍历一个文本文件,其中包含我想要访问的URL:s并截图 所有这些都很简单。该脚本初始化一个类,该类在运行时创建列表中每个站点的屏幕截图。有些站点需要很长很长时间才能加载,有些站点可能根本无法加载。因此,我想将screengrabber函数包装在一个超时脚本中,如果它不能在10秒内完成,则使函数返回Python 超时功能,如果完成时间过长,python,Python,我有一个shell脚本,它循环遍历一个文本文件,其中包含我想要访问的URL:s并截图 所有这些都很简单。该脚本初始化一个类,该类在运行时创建列表中每个站点的屏幕截图。有些站点需要很长很长时间才能加载,有些站点可能根本无法加载。因此,我想将screengrabber函数包装在一个超时脚本中,如果它不能在10秒内完成,则使函数返回False 我对最简单的解决方案很满意,也许设置一个异步计时器,10秒后不管函数内部实际发生了什么都会返回False?操作超时的过程在的文档中描述 其基本思想是使用信号处理
False
我对最简单的解决方案很满意,也许设置一个异步计时器,10秒后不管函数内部实际发生了什么都会返回False?操作超时的过程在的文档中描述 其基本思想是使用信号处理程序为某个时间间隔设置警报,并在计时器过期时引发异常 请注意,这只适用于UNIX 下面是一个创建装饰器的实现(将以下代码另存为
timeout.py
)
这将创建一个名为@timeout
的修饰符,该修饰符可应用于任何长时间运行的函数
因此,在应用程序代码中,您可以像这样使用装饰器:
from timeout import timeout
# Timeout a long running function with the default expiry of 10 seconds.
@timeout
def long_running_function1():
...
# Timeout after 5 seconds
@timeout(5)
def long_running_function2():
...
# Timeout after 30 seconds, with the error "Connection timed out"
@timeout(30, os.strerror(errno.ETIMEDOUT))
def long_running_function3():
...
我使用
with
语句重写了David的答案,它允许您这样做:
with timeout(seconds=3):
time.sleep(4)
这将引发超时错误
代码仍在使用信号
,因此仅限UNIX:
import signal
class timeout:
def __init__(self, seconds=1, error_message='Timeout'):
self.seconds = seconds
self.error_message = error_message
def handle_timeout(self, signum, frame):
raise TimeoutError(self.error_message)
def __enter__(self):
signal.signal(signal.SIGALRM, self.handle_timeout)
signal.alarm(self.seconds)
def __exit__(self, type, value, traceback):
signal.alarm(0)
注意这不是线程安全的:如果使用多线程,信号将被随机线程捕获。但是对于单线程程序,这是最简单的解决方案。很好。此外,建议使用
@functools.wrapps(func)
FYI装饰函数包装器
,以供参考,在第一个“@timeout”之后缺少包装。它应该是@timeout()def…
@wim我认为它只能在主线程中使用,因为如果在工作线程中使用它,它将引发“ValueError:signal only works in main thread”。在使用线程时,有什么可行的替代方法呢?Python@timeout.timeout
作为一个静态方法。然后,您可以很容易地在decorator和with
语句之间进行选择。有趣的是,如果在with Timeout(t)
上下文中引发了任何错误,则仍然会调用\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
,从而避免了由引发的TimeOutError
而不是真正的错误引起的任何复杂情况。这是一个非常可爱的解决方案。有人能推荐一个可行的解决方案,像这样,在线程中工作吗?@Nick前段时间我创建了一个超时装饰器版本,它与浮动一起工作-适用于所有懒惰的人,他们喜欢使用库,而不是从StackOverflow复制+粘贴代码片段:
import signal
class timeout:
def __init__(self, seconds=1, error_message='Timeout'):
self.seconds = seconds
self.error_message = error_message
def handle_timeout(self, signum, frame):
raise TimeoutError(self.error_message)
def __enter__(self):
signal.signal(signal.SIGALRM, self.handle_timeout)
signal.alarm(self.seconds)
def __exit__(self, type, value, traceback):
signal.alarm(0)