繁体   English   中英

Python 0xC00000FD 无线程修复

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM