![](/img/trans.png)
[英]Process finished with exit code -1073741571 (0xC00000FD) in Python
[英]Python 0xC00000FD fix without thread
我有一个程序需要进行非常深的递归。 我使用sys.setrecursionlimit(10**6)
将递归限制增加到 10**6 。 但是,该过程退出并显示以下错误代码:
Process finished with exit code -1073741571 (0xC00000FD)
阅读this question后,结果证明递归限制不会改变堆栈大小,因此发生堆栈溢出。 这个问题的解决方案是使用threading.stack_size()
,但是我是 Python 的初学者,所以我不明白如何使用线程。
那么如何在主线程上修复 0xC00000FD 呢?
我检查过多次——我没有无限循环,只是我的递归很深。
我有点惊讶地发现设置线程堆栈大小有效(在我的 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)
如果您最终不得不将递归函数转换为迭代方法,则此装饰器/类可能有助于减轻痛苦(取决于递归的性质)。
装饰器将函数中的递归调用转换为具有内部(无限)堆栈的迭代调用。 它的主要限制是它只支持简单的递归,其中自调用是 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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.