【问题标题】:Python 3: Why are loops faster than recursions? [duplicate]Python 3:为什么循环比递归快? [复制]
【发布时间】:2019-07-17 09:51:03
【问题描述】:

我比较了循环和递归的运行时间,发现循环速度更快,同时没有遇到 RecursionError 的问题。为什么循环这么快?

def factorial(n):
   if n == 0:
      return n
   else:
      return n + factorial(n-1)

%%timeit -n1000 -r10000
factorial(1000)

每个循环 163 µs ± 13.2 µs(10000 次运行的平均值 ± 标准偏差,每次 1000 个循环)

def factorial2(n):
   r = 0
   for i in range(n+1):
      r += i
   return r

%%timeit -n1000 -r10000
factorial2(1000)

最慢的运行时间是最快的运行时间的 9.46 倍。这可能意味着正在缓存中间结果。 每个循环 58.7 µs ± 25.2 µs(10000 次运行的平均值 ± 标准偏差,每次 1000 个循环)

感谢和愉快的编码!

【问题讨论】:

  • 一般来说,使用递归,运行时必须做额外的工作,将变量推送到堆栈帧,然后进行函数调用,这会增加执行时间。即使您一遍又一遍地调用相同的函数,使用递归,每次调用都会创建所有局部变量的新范围。通过迭代,不需要完成额外的工作。
  • 你的factorial实际上是在计算0 -> n btw之间的总和
  • 函数调用在 Python 中非常昂贵。一个神话是 Python 中的 for 循环很慢,但如果循环包含函数调用甚至方法调用,情况就很普遍。请参阅 wiki.python.org/moin/PythonSpeed/PerformanceTipspython.org/doc/essays/list2str 。所以r += i 比调用n + factorial(n-1) 快很多。顺便说一句,阶乘不应该使用乘法吗?

标签: python python-3.x algorithm loops recursion


【解决方案1】:

一般来说,除非特定的编程语言支持快速递归,否则递归总是会变慢。当程序进行函数调用时,会创建一个新的堆栈帧,其中存储所有局部变量。在迭代过程中,一切都发生在一个堆栈帧内。

有一种叫做“尾递归”的东西,其中函数的编写方式使得计算结果始终在最后一帧中可用 - 所以理论上,只有 1 个堆栈帧就足够了。在某些语言中,编译器识别出这种情况并将递归转换为“幕后”迭代——这种类型的递归确实与迭代一样快。不幸的是,Python3 不支持尾递归。

【讨论】:

    猜你喜欢
    • 2013-05-04
    • 1970-01-01
    • 2011-02-08
    • 1970-01-01
    • 2021-04-18
    • 2016-05-14
    • 1970-01-01
    相关资源
    最近更新 更多