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安装的)。你不是在线程中运行这段代码的吧?因为这会让事情变得更复杂。这只是一个概念证明。