为什么 @lru_cache 会导致深度递归栈溢出,而普通递归不会?-Python教程

python 中 `@lru_cache` 的底层 c 实现会额外占用 c 栈空间,导致即使 python 层递归深度相同,c 层栈也极易溢出;而纯 python 递归在 3.11+ 已通过内联调用优化避免了 c 栈消耗,因此更耐深递归。

在解决树形动态规划(如 CSES 1674:统计每个员工的下属人数)时,你可能会自然写出递归 DFS,并尝试用 @lru_cache 加速。但令人困惑的是:*完全相同的树结构、相同的递归逻辑、甚至相同的 `sys.setrecursionlimit(2 109)设置,加了@lru_cache就崩溃(0xC00000FD`),不加却能稳定运行百万级节点——这并非算法问题,而是 Python 运行时底层机制的差异所致。

? 根本原因:C 栈 vs Python 栈

  • functools.lru_cache 在 CPython 3.11 及更早版本中是 纯 C 实现(见 _functoolsmodule.c),每次被装饰函数调用时,都会触发一次 C 函数调用链(_lru_cache_wrapper → 原函数)。这意味着:
    ✅ 每次递归不仅压入 Python 栈帧,还压入一个 C 栈帧;
    ❌ C 栈默认大小极小(Windows/Linux 通常仅 1–8 MB),对应安全递归深度仅数千到数万;
    ⚠️ 即使你用 sys.setrecursionlimit(2e9) 抬高 Python 限制,CPython 3.11 仍会盲目尝试执行超深 C 递归,最终 C 栈溢出,进程被操作系统强制终止(退出码 0xC00000FD)。

  • 而纯 Python 递归(无装饰器)在 Python 3.11+ 中已启用 Inlined Python Function Calls(PEP 659 优化):当 Python 函数直接调用另一个 Python 函数时,解释器可跳过 C 层调度,复用当前 C 栈帧,仅增长 Python 栈。因此:

    • sys.setrecursionlimit() 对其生效;
    • 实际 C 栈深度几乎恒定(≈1),真正受限的是 Python 栈(可通过 setrecursionlimit 扩展);
    • 故 200,000 层递归轻松通过,甚至测试 20,000,000 层也不会崩溃(只会抛 RecursionError)。

? 验证:Python 3.12 的行为变化

Python 3.12 明确分离了限制机制(What’s New):

“The recursion limit now applies only to Python code. Built-in functions do not use the recursion limit, but are protected by a different mechanism…”

这意味着:

夏夕资源网专注于CMS网站模板,主流语言整站网站源码下载,网站建设相关教程分享,好用的软件素材整合下载,提供一站式便捷自助服务。
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,默认解压密码为"zy.lucklyus.top",如遇到无法解压的请联系管理员!
夏夕资源网-网站模板_免费源码_资源素材 » 为什么 @lru_cache 会导致深度递归栈溢出,而普通递归不会?-Python教程
在线时间:12:00 - 22:00
关注微信公众号:微信公众号
站长邮箱:[email protected]
  • 运营天数: 1392+
  • 资源总数: 47989+
  • 用户总数: 1+
  • 今日更新: 0+
  • 访问次数: 4005680+
  • 本周更新: 0+
  • 最后更新: 2026-03-16

本站指数

×
  • 运营天数: 1392+
  • 资源总数: 47989+
  • 用户总数: 1+
  • 今日更新: 0+
  • 访问次数: 4005681+
  • 本周更新: 0+
  • 最后更新: 2026-03-16