リンク内のjavascriptを再帰的に分析するスクリプトがあるので、javascriptが見つかった場合は、javascriptを分析し、分析しているjavascriptにさらにjavascriptが含まれている場合は、続行します。ただし、この再帰が停止しないという問題が発生しました。この再帰のタイムアウトを追加する方法はありますか?
4 に答える
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()
既に見たアイテムの 1 つを保持し、既に処理したアイテムの処理を単に拒否することです。これにより、そもそも再帰的な状況に陥るのを防ぐことができます。
私は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)
手っ取り早い解決策は、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 で終了します。
明らかに、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(...)
...それはやり過ぎかもしれませんが。