如何为复杂的计算设置超时时间?

时间:2018-07-10 09:44:55

标签: python python-3.x

我正在编写类似的程序

results = []
for i in range(30):
    x = 4 ** 5 ** i
    results.append(x)

但是,当i变大(并且结果不会太大而不能筹集OverflowError)时,将需要很长的时间来计算结果。因此,我想设置一个超时机制,如果计算时间超过1秒,该机制将continue

我尝试使用eventlet这样的软件包

from eventlet import Timeout
with Timeout(1) as timeout:
    x = 4 ** 5 ** 20

但是timeout无法正常工作。 (也许只是因为我只执行一行代码。)我从StackOverflow发现的其他方法也失败了……

是否存在一种可能的编程方式来为此“简单但复杂”的计算设置超时?或者,还有其他方法吗? (例如,结果太大时退出...)

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

首先,尝试为此使用eventlet是错误的工具。 eventlet主要用于使用以greenlets形式的协程进行非阻塞I / O。与CPU相关的问题无关(实际上,eventlet.Timeout的文档已阅读):

  

如果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

注意:,这仅适用于* NIX系统,尽管也可以在Windows上进行。