首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >不带线程的Python 0xC00000FD修复

不带线程的Python 0xC00000FD修复
EN

Stack Overflow用户
提问于 2021-10-25 05:21:41
回答 2查看 94关注 0票数 1

我有一个程序需要做非常深的递归。我使用sys.setrecursionlimit(10**6)将递归限制增加到10**6。但是,进程退出时返回以下错误代码:

代码语言:javascript
复制
Process finished with exit code -1073741571 (0xC00000FD)

读取this question后,发现递归限制不会改变堆栈大小,因此发生了堆栈溢出。这个问题的解决方案是使用threading.stack_size(),但是我是Python的初学者,所以我不知道如何使用线程。

那么如何在主线程上修复0xC00000FD呢?

我已经检查了很多次了-我没有无限循环,只是我的递归非常深。

编辑2021年10月30日:这里的许多人建议重写代码,使用迭代(循环)而不是递归,所以我这样做了。现在我的代码可以正常工作了,不再出现堆栈溢出错误。但如果有人知道如何增加主线程栈的大小,请在这里自由回答,我仍然很好奇是否有任何方法可以增加python主线程栈的大小,因为在我学习的其他语言(如java )上,增加主线程栈的大小是可能的。

EN

回答 2

Stack Overflow用户

发布于 2021-10-25 06:15:29

我有点惊讶地发现设置线程堆栈大小起作用了(在我的Linux机器上,我想Windows也可以)。我写了一个测试,在有线程和没有线程的情况下进行递归,结果是:

代码语言:javascript
复制
$ 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的类。初始化器启动并加入自己的线程,所以只需实例化它,您就可以开始比赛了。堆栈大小控制是线程模块的全局控制-令人困惑的是线程模块本身不是线程安全的-所以它是在启动代码之前设置的,并在运行时重置。

代码语言:javascript
复制
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)
票数 1
EN

Stack Overflow用户

发布于 2021-10-25 16:06:04

如果您最终不得不将递归函数转换为迭代方法,此修饰器/类可能有助于减轻痛苦(取决于递归的性质)。

装饰器将函数中的递归调用转换为具有内部(无限制)堆栈的迭代调用。它的主要限制是,它只支持简单的递归,其中自调用是return语句的一部分,并且它需要更改return语句的表达方式。此外,它还会显著增加函数调用的开销,从而影响性能。

使用模式如下:

代码语言:javascript
复制
@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

例如:

代码语言:javascript
复制
@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 ...

以下是装饰器/类:

代码语言:javascript
复制
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)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69703183

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档