我有一个脚本,可以递归地分析链接中的 javascript,所以如果它找到一个 javascript,那么它会分析 javascript,如果它正在分析的 javascript 包含更多的 javascript,那么它会继续运行,依此类推。但是,我遇到了这个递归永远不会停止的问题,有没有办法为这个递归添加超时?
问问题
1294 次
4 回答
6
Python 有一个内置的递归限制,RuntimeError
如果超过这个限制,就会引发 a。默认情况下,它的堆栈限制为 1000。所以:
try:
func_that_may_recurse_infinitely() # i.e., your JavaScript crawler func
except RuntimeError as e:
if "recursion" in str(e):
print "stop all the downloadin'!"
sys.setrecursionlimit()
如果需要更深或更浅,您可以修改初始递归限制。
但是,更好的方法可能是保留set()
您已经看到的项目,并简单地拒绝处理您已经处理的任何项目。这可以防止您首先陷入递归情况。
于 2012-07-17T18:10:11.243 回答
2
我倾向于同意kindall。但是,如果您确实想限制递归的深度,则可以执行以下操作:
def foo(max_depth = 10, cur_depth=0):
if cur_depth >= max_depth:
return BASE_CASE
else:
return foo(max_depth, cur_depth+1)
于 2012-07-17T18:14:08.677 回答
2
一个快速而肮脏的解决方案是调用 time.time() 并进行比较。例如,假设您有一个简单的阶乘函数,如下所示:
def fact(i):
if i == 0 or i == 1: return 1
return i * fact(i-1)
如果您调用 fact(-1),这将旋转一段时间,然后由于最大递归深度而引发 RuntimeError。
您可以像这样添加超时:
import time
def factWithTimeout(i, timeout):
def fact(i, endtime):
if time.time() > endtime:
raise RuntimeError('Timeout')
if i == 0 or i == 1: return 1
return i * fact(i-1, endtime)
return fact(i, time.time() + timeout)
现在,如果您调用factWithTimeout(-1, 0.0001)
,它只会旋转大约 100us,然后由于超时而退出 RuntimeError。
显然,对于一个如此微不足道的函数,它会在一毫秒内达到递归限制,这并没有太大的不同,但对于一个更现实的函数,这将不是问题。
于 2012-07-17T18:20:43.563 回答
1
你可以这样做:
import time
start = time.time()
timeout_limit = 30 # 30 seconds, or some other number.
def foo():
if time.time() > start + timeout_limit:
return 0
# insert code here.
foo()
...如果你不想要全局变量,你可以试试这个:
class Foo(object):
def __init__(self, timeout_limit):
self.timeout_limit = timeout_limit
def run(self, ...):
self.start = time.time()
self._run(...)
def _run(self, ...):
if time.time() > self.start + self.timeout_limit:
return
# insert code here.
self._run(...)
...虽然这可能是矫枉过正。
于 2012-07-17T18:13:13.630 回答