Python 如何为复杂的计算设置超时?
我正在写一个像这样的程序Python 如何为复杂的计算设置超时?,python,python-3.x,Python,Python 3.x,我正在写一个像这样的程序 results = [] for i in range(30): x = 4 ** 5 ** i results.append(x) 但是,当i变大时(并且结果不会太大而导致溢出错误),计算结果将花费很长的时间。因此,我想设置一个超时机制,如果计算时间超过(比如)1秒,它将继续 我尝试使用eventlet包 from eventlet import Timeout with Timeout(1) as timeout: x = 4 ** 5 *
results = []
for i in range(30):
x = 4 ** 5 ** i
results.append(x)
但是,当i
变大时(并且结果不会太大而导致溢出错误
),计算结果将花费很长的时间。因此,我想设置一个超时机制,如果计算时间超过(比如)1秒,它将继续
我尝试使用eventlet
包
from eventlet import Timeout
with Timeout(1) as timeout:
x = 4 ** 5 ** 20
但是超时
不起作用。(可能只是因为我只执行了一行代码。)我从StackOverflow找到的其他方法也失败了
是否有一种可能的编程方法来设置“简单但复杂”计算的超时?或者,还有别的办法吗?(例如,当结果太大时退出…)
谢谢你的帮助 首先,尝试使用
eventlet
,因为这是错误的工具eventlet
主要用于使用greenlet形式的协程的非阻塞I/O。这与CPU限制的问题没有什么关系(事实上,eventlet.Timeout
read的文档):
如果try/finally或with块中的代码块从未协同生成,则无法引发超时。在Eventlet中,这应该很少是一个问题,但是请注意,您不能用这个类超时仅CPU的操作
这意味着,如果您有一些代码块正在执行CPU限制的操作,您仍然不会跳出它,因为代码永远不会让位于另一个线程。这更适用于您可能有一些代码的情况,例如,检查套接字是否有数据可读取,如果没有,则生成
如果要在一段时间后设置中断以中断长时间运行的计算,可以使用signal.alarm
并设置SIGALRM
处理程序。您可以在上下文管理器中完成这一切,如:
>>> import signal
>>> from contextlib import contextmanager
>>> class TimeoutError(RuntimeError): pass
...
>>> @contextmanager
... def timeout(seconds):
... def handler(*args):
... raise TimeoutError("timed out after {} seconds".format(seconds))
... orig_handler = signal.signal(signal.SIGALRM, handler)
... signal.alarm(seconds)
... try:
... yield
... finally:
... signal.alarm(0)
... signal.signal(signal.SIGALRM, orig_handler)
...
>>> with timeout(10):
... while True: pass
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 4, in handler
__main__.TimeoutError: timed out after 10 seconds
>>> with timeout(10):
... print(1 + 1)
...
2
>>> with timeout(10):
... 4 ** 5 ** 20
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 4, in handler
__main__.TimeoutError: timed out after 10 seconds
导入信号
>>>从contextlib导入contextmanager
>>>类TimeoutError(RuntimeError):通过
...
>>>@contextmanager
... def超时(秒):
... def处理程序(*args):
... raise TimeoutError(“在{}秒之后超时”。格式(秒))
... orig_handler=signal.signal(signal.SIGALRM,handler)
... 信号报警(秒)
... 尝试:
... 产量
... 最后:
... 信号报警(0)
... signal.signal(signal.SIGALRM,原始处理器)
...
>>>带超时(10):
... 虽然正确:通过
...
回溯(最近一次呼叫最后一次):
文件“”,第2行,在
文件“”,第4行,在处理程序中
__主计时器错误:10秒后超时
>>>带超时(10):
... 打印(1+1)
...
2.
>>>带超时(10):
... 4 ** 5 ** 20
回溯(最近一次呼叫最后一次):
文件“”,第2行,在
文件“”,第4行,在处理程序中
__主计时器错误:10秒后超时
注意:这只适用于*NIX系统,尽管在Windows上也有这样做的方法。python中的power操作符与其他任何操作符不同,是右关联的。这意味着
a**b**c==a**(b**c)
。因为5**20==9.536743e+13
这意味着4**5**20
的长度将为10^26位。您的计算机大约有10^11位内存。与其暂停这个操作(这需要某种线程),不如在你得不到答案的时候不要这样做。谢谢。实际上,我在每个循环中都面对一个字符串,并使用eval
对其求值。。。有些计算非常微妙,无法引发溢出错误。如何建立一个标准将是一个问题…您正在使用eval?对我在一些文章中发现了eval
,而eval
可能是一些问题的“快速而肮脏”的解决方案(尽管它非常糟糕)。。。我也可以找到另一种方法来解决我的问题。但是这个问题在没有eval
的情况下仍然存在。很抱歉,如果我运行4**5**20
它就不起作用了。它对我有效。您使用的是什么Python版本?你认为超时是什么?我在Linux上使用Python3.6.3(Ubuntu16.04 LTS),我将超时设置为3秒。它只是卡在那里。@YuzhangXie请看这个日志:(这是Python 3.6.5而不是3.6.3,但我不认为这有什么区别——我也不知道你是如何安装Python 3.6的;我必须从PPA安装的)。你不是在线程中运行这段代码的吧?因为这会让事情变得更复杂。这只是一个概念证明。