Timeout function if it takes too long to finish
本问题已经有最佳答案,请猛点这里访问。
我有一个shell脚本,它循环遍历一个包含URL:s的文本文件,我想访问这个文件并截屏。
所有这些都很简单。脚本初始化一个类,当运行该类时,该类将创建列表中每个站点的屏幕截图。有些站点需要非常、非常长的时间来加载,有些站点可能根本就没有加载。因此,我想将screengrabber函数封装在超时脚本中,如果它不能在10秒内完成,那么函数将返回
我满足于最简单的解决方案,也许设置一个异步计时器,无论函数内部实际发生什么,10秒后都会返回False ?
在signal文档中描述了操作超时的过程。
基本思想是使用信号处理程序设置某个时间间隔的警报,并在计时器过期时引发异常。
注意,这只适用于UNIX。
下面是一个创建装饰器的实现(将以下代码保存为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | from functools import wraps import errno import os import signal class TimeoutError(Exception): pass def timeout(seconds=10, error_message=os.strerror(errno.ETIME)): def decorator(func): def _handle_timeout(signum, frame): raise TimeoutError(error_message) def wrapper(*args, **kwargs): signal.signal(signal.SIGALRM, _handle_timeout) signal.alarm(seconds) try: result = func(*args, **kwargs) finally: signal.alarm(0) return result return wraps(func)(wrapper) return decorator |
这将创建一个名为
所以,在你的应用程序代码中,你可以这样使用装饰器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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(): ... |
我用
1 2 | with timeout(seconds=3): time.sleep(4) |
这会引起时间恐慌。
代码仍然使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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) |