我有一个程序需要做非常深的递归。我使用sys.setrecursionlimit(10**6)将递归限制增加到10**6。但是,进程退出时返回以下错误代码:
Process finished with exit code -1073741571 (0xC00000FD)读取this question后,发现递归限制不会改变堆栈大小,因此发生了堆栈溢出。这个问题的解决方案是使用threading.stack_size(),但是我是Python的初学者,所以我不知道如何使用线程。
那么如何在主线程上修复0xC00000FD呢?
我已经检查了很多次了-我没有无限循环,只是我的递归非常深。
编辑2021年10月30日:这里的许多人建议重写代码,使用迭代(循环)而不是递归,所以我这样做了。现在我的代码可以正常工作了,不再出现堆栈溢出错误。但如果有人知道如何增加主线程栈的大小,请在这里自由回答,我仍然很好奇是否有任何方法可以增加python主线程栈的大小,因为在我学习的其他语言(如java )上,增加主线程栈的大小是可能的。
发布于 2021-10-25 06:15:29
我有点惊讶地发现设置线程堆栈大小起作用了(在我的Linux机器上,我想Windows也可以)。我写了一个测试,在有线程和没有线程的情况下进行递归,结果是:
$ python3 recurse.py
Testing unthreaded
try 10**4
10000
try 10**5
Segmentation fault (core dumped)
$ python3 recurse.py threaded
Testing threaded
try 10**4
10000
try 10**5
100000
try 10**6
Exception in thread Thread-3:
...
RecursionError: maximum recursion depth exceeded in comparison代码创建了一个继承自threading.Thread的类。初始化器启动并加入自己的线程,所以只需实例化它,您就可以开始比赛了。堆栈大小控制是线程模块的全局控制-令人困惑的是线程模块本身不是线程安全的-所以它是在启动代码之前设置的,并在运行时重置。
import threading
import sys
# usage: recurse.py [threaded]
sys.setrecursionlimit(10**6)
class MyRecursionThread(threading.Thread):
"""Start the recursion function in a separate thread and
wait til complete"""
def __init__(self, depth):
super().__init__()
self.orig_stack_size = threading.stack_size()
threading.stack_size(100000*4096) # guessing here
self.depth = depth
self.start()
self.join()
def run(self):
# thread is started so return default. Why isn't this
# thread safe in the threading module!?!
threading.stack_size(self.orig_stack_size)
self.result = the_recursive_function(0, self.depth)
def the_recursive_function(cur, depth):
if cur < depth:
return the_recursive_function(cur+1, depth)
else:
return cur
# probe depth
try:
threaded = sys.argv[1] == "threaded"
except IndexError:
threaded = False
print("Testing", "threaded" if threaded else "unthreaded")
for i in range(4, 8):
print(f"try 10**{i}")
if threaded:
result = MyRecursionThread(10**i).result
else:
result = the_recursive_function(0, 10**i)
print(result)发布于 2021-10-25 16:06:04
如果您最终不得不将递归函数转换为迭代方法,此修饰器/类可能有助于减轻痛苦(取决于递归的性质)。
装饰器将函数中的递归调用转换为具有内部(无限制)堆栈的迭代调用。它的主要限制是,它只支持简单的递归,其中自调用是return语句的一部分,并且它需要更改return语句的表达方式。此外,它还会显著增加函数调用的开销,从而影响性能。
使用模式如下:
@iterative # decorator to modify the function
def fn(...) # existing declaration
... # and implementation
if baseCase return x # no change to the base case
return fn(...),lambda x: ... # isolate alterations to the recursed
# result in a lambda例如:
@iterative
def factorial(n):
if n<2: return 1
return factorial(n-1),lambda f:f*n
print(factorial(10)) # 3628800
print(len(str(factorial(10000)))) # 10000! has 35660 digits
@iterative
def sumSquares(n):
if n<2: return n
return sumSquares(n-1),lambda f:f+n**2
print(sumSquares(1000000)) # 333333833333500000
@iterative
def fibo(n):
if n<2: return n
return fibo(n-1),fibo(n-2),lambda n1,n2: n1+n2
print(fibo(10)) # 55
print(fibo(1000)) # will work, ... waiting for output ...以下是装饰器/类:
from collections import deque
class iterative:
def __init__(self,func):
self.func = func # decorated function
self.stack = deque() # [(argCount, function to call)]
self.nested = False # nested call flag
self.recursed = False # call wants recursion
self.results = [] # result stack
def __call__(self,*args,**kwargs): # replaces original function
if self.nested:
self.recursed = True # defer recursive call to make
return lambda: self.func(*args,**kwargs)
else:
self.nested = True
self.stack.append((0,lambda: self.func(*args,**kwargs))) # top
while self.stack:
useArgs,fn = self.stack.pop() # unstack
if useArgs: # lambda on results
args = self.results[-useArgs:]
self.results = self.results[:-useArgs]
self.results.append(fn(*args))
else:
self.recursed = False # recursive call
result = fn()
if self.recursed: # more recursion -> stack
*calls,final = result
self.stack.append((len(calls),final))
self.stack.extend([(0,r) for r in reversed(calls)])
else:
self.results.append(result) # base cond. -> results
self.nested = False
return self.results.pop(-1) # final result (and reset)https://stackoverflow.com/questions/69703183
复制相似问题