开发手册 欢迎您!
软件开发者资料库

Python 递归次数和性能问题优化解决方法

假设我们要用递归计算斐波那契数列,C++中没什么问题性能很好,但Python中次数比较多情况下,性能有问题。本文主要介绍Python 递归次数限制和性能问题优化解决方法,以及相关的示例代码。

C++和Python中递归实现计算斐波那契数列,当n=500时,两者都能正常计算,例如,

#include #include using namespace std;array fib(unsigned n) {    if (!n)        return {1, 1};    auto x = fib(n - 1);    return {(x[0] + x[1]) % 997, (x[0] + 2 * x[1]) % 997};}int main() {    cout << fib(500)[0];}

 但当n=5000,C++能正常计算,Python会报错:RecursionError: maximum recursion depth exceeded in comparison

但可以通过增加sys.setrecursionlimit(6000),例如,

import sysdef fib(n):    if n==1:        return (1, 2)    x=fib(n-1)    return ((x[0]+x[1]) % 997, (x[0]+2*x[1]) % 997)if __name__=='__main__':    sys.setrecursionlimit(6000)    print(fib(5000)[0])

然而,当n=50000,Python在我机器上崩溃了,而C++几毫秒得出结果151 。对于斐波那契数列,解决方案是用迭代代替递归。但其它递归问题可能就不这么容易了。下面在看一下问题原因及解决办法。

问题原因:

Python 对递归函数调用的数量有内部限制。该限制是可配置的,但是,函数链太深会导致堆栈溢出。这种潜在的限制¹适用于 C++ 和 Python。此限制也适用于所有函数调用,而不仅仅是递归调用。潜在的限制是执行堆栈大小。默认大小因系统而异,不同的函数调用消耗不同的内存量,因此限制不是指定为调用次数,而是以字节为单位。这在某些系统上也是可配置的。由于便携性问题,通常不建议修改该限制。C++对递归调用深度没有限制,除了栈的大小。作为一种完全编译的语言,循环(包括递归)在 C++ 中比在 Python 中快得多。

解决方法:

将递归函数转换为一个可以跟踪a和b作为参数的版本,使其成为尾递归。

例如,

def fib_acc(n, a, b):    if n == 1:        return (a, b)    return lambda: fib_acc(n - 1, (a+b) % 997, (a+2*b) % 997)def fib(n):    x = fib_acc(n, 1, 2)    while callable(x):        x = x()    return xif __name__=='__main__':    print(fib(50000)[0])