【问题标题】:Is there something wrong with this python code, why does it run so slow compared to ruby?这段 python 代码有问题吗,为什么它的运行速度比 ruby​​ 慢?
【发布时间】:2011-05-02 02:00:29
【问题描述】:

我对比较 ruby​​ 和 python 的速度很感兴趣,所以我采用了最简单的递归计算,即打印斐波那契数列。

这是python代码

#!/usr/bin/python2.7                       
def fib(n):
    if n == 0: 
        return 0
    elif n == 1:
        return 1 
    else:
        return fib(n-1)+fib(n-2)

i = 0
while i < 35:
    print fib(i)
    i = i + 1

这是红宝石代码

#!/usr/bin/ruby

def fib(n)
    if n == 0
        return 0
    elsif n == 1
        return 1
    else
        fib(n-1)+fib(n-2)
    end
end 

i = 0 
while (i < 35)
    puts fib(i)
    i = i + 1 
end

经过多次运行,时间报告了这个平均值

real    0m4.782s 
user    0m4.763s 
sys     0m0.010s

这就是 ruby​​,现在 python2.7 给了

real    0m11.605s
user    0m11.563s
sys     0m0.013s

怎么了?

【问题讨论】:

  • 我只想指出,在独立于语言的意义上,迭代计算会快得多。在这里使用递归会导致重复计算相同的值。
  • 我不会列出答案,因为我不知道确切的原因,但它可能是 ruby​​ 编译器有一些 Python 没有的优化。使用递归的幼稚 fib 函数会创建一些语言无法很好处理的巨大调用堆栈。特别是,该语言通常必须实现尾调用递归优化,以高效地处理此类情况,并且在大量递归下不会出现堆栈溢出。
  • 我同意 CodexArcanum。这可能是密切相关的:stackoverflow.com/questions/824562/…
  • @Codex:这里没有什么可以进行尾调用优化的。该定义不是尾递归的。
  • 为什么要循环播放? fibo = lambda n: int((((1 + math.sqrt(5)) / 2)**n + (1/((1 + math.sqrt(5)) / 2))**n) / math.sqrt(5) + 0.5)

标签: python ruby performance fibonacci


【解决方案1】:

python 的递归效率是造成这种开销的原因。有关更多详细信息,请参阅this article。上述迭代解决这个问题的解决方案对于 python 来说更好,因为它们不会产生函数调用开销递归。我对 ruby​​ 的假设是它显然在优化代码,而 python 没有。同样,该文章使用几乎相同的 fib 函数对此进行了详细介绍。

【讨论】:

  • 我也喜欢你链接的那篇文章中的 cmets。这确实为在 python 中使用递归函数调用提供了一些启示。
【解决方案2】:

因此,对于这段代码,Python 比 Ruby 慢两倍多一点。可能对于其他代码,Python 会比 Ruby 更快。

您的 fib() 实现具有指数级的运行时间。这可以通过使用循环轻松避免。 Python 示例:

a, b = 1, 1
for i in range(35):
    a, b = b, a+b
print b

【讨论】:

  • 问题不在于如何编写高效的 fib() 实现。问题是为什么在 Python(如果是的话)中创建巨大的调用堆栈比在 Ruby 中更昂贵。
  • 我的主要观点实际上应该是观察到的差异很小——它只是两倍,这一点也不奇怪。再看我的帖子,我觉得别人的cmet更好,但我还是放在那里吧:)
【解决方案3】:

您计算斐波那契数列中前 35 个数字的方法效率极低。你运行一个函数 fib() 35 次,每次 fib() 都有指数运行时间。 Python 中的生成器是这个问题的完美解决方案,并且比您在 Ruby 中编写的要高效得多。

def fibo_generator(n):
    # gets Fibonacci numbers up to nth number using a generator
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

然后,您可以使用此代码打印最多 35 的所有斐波那契数:

for f in fibo_generator(35):
    print f

这是迄今为止在 Python 中实现斐波那契数列最有效的方法,也是最通用的方法。

【讨论】:

  • 我不想要最高效的编程语言 x,我想知道为什么几乎完全一样的 python 和 ruby​​ 程序在非常不同的时间范围内运行。 ruby 版本是否优化了我背后的代码?虽然我们正在这样做,但我认为记忆化会大大加快速度。
  • 查看 THC4k 的回答,了解为什么这个测试没有任何意义。这并不意味着 Python 比 Ruby 慢,因为您的应用程序没有多大意义。为什么你会做任何语言都低效的事情?当你发挥 Python 的优势时,它的速度是最快的,Ruby 也是如此。
【解决方案4】:

我对比较 ruby​​ 很感兴趣 速度与 python

微基准测试是比较语言的一种非常糟糕的方法,尤其是在您掌握这两种语言之前。如果您想要一个具有任何现实意义的基准,那么您需要付出很多努力 - 或者您 google for "language shootout"

这里是Python and Ruby的更好比较

【讨论】:

  • 为什么这是比较语言的不好方法?与python中几乎相同的代码相比,ruby的速度是什么原因?我知道可以使用生成器、记忆等来更好地提供序列......但我感兴趣的是 - 为什么相同的代码会有这么大的差异?
  • @AntonioP:因为只有初学者才能编写这样的代码。您的基准测试只告诉您“这个糟糕的 Python 程序比那个糟糕的 Ruby 程序慢”。只有比较最快的实现才有意义,而不是使用相同的代码。
  • 我必须同时同意和不同意。确实,比较糟糕的程序并没有帮助。但是,我不同意您应该比较最快的实现。我认为您应该比较设计最完善的实现。编译器编写者的工作是确保设计得最好的实现也是最快的,但如果它不是,那么你不应该优化代码,你应该修复编译器。
  • @Jörg W Mittag:是的,我完全同意你的看法。
  • @Jörg W Mittag:对于哪些是“设计最完善的实现”,不同的人可能会有不同的看法。
【解决方案5】:

这里还有一些数字可供比较:

Python2.7
9.67 用户 0.09 系统 0:09.78 经过 99%CPU (0avgtext+0avgdata 16560maxresident)k
0输入+0输出(0主要+1169次要)页面错误0交换

ruby 1.8.7 (2010-06-23 补丁级别 299) [x86_64-linux]
28.37 用户 0.35 系统 0:28.78 经过 99% CPU (0avgtext+0avgdata 9200maxresident)k
1896 输入 + 0 输出(9 主要 + 656 次要)页面错误 0 交换

ruby 1.9.2p0(2010-08-18 修订版 29036)[x86_64-linux]
6.21 用户 0.08 系统 0:06.36 经过 98% CPU (0avgtext+0avgdata 14160maxresident)k
4416 输入 + 0 输出(16 主要 + 953 次要)页面错误 0 交换

对于所提供的代码,Python 比 ruby​​1.8三倍,比 ruby​​1.9.1 慢 30%。

用于比较的其他 Python 版本:

2.4.6 耗时 10.30 秒

2.5.5 耗时 9.93 秒

2.6.6 耗时 9.22 秒

2.7 耗时 9.35 秒

3.0.1 耗时 11.67 秒

3.1.2 耗时 11.35 秒

3.2a3+ (py3k:85895, 2010 年 10 月 29 日, 01:41:57)
[GCC 4.4.5] 耗时 13.09 秒

2.5.2 (77963, 2010 年 10 月 15 日, 02:00:43)
[PyPy 1.3.0] 耗时 21.26 秒

2.5.1(Release_2_5_1:6813,2009 年 9 月 26 日,13:47:54)
[OpenJDK 64-Bit Server VM (Sun Microsystems Inc.)] 耗时 8.81 秒

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-24
    • 2017-11-04
    • 2022-01-19
    • 1970-01-01
    • 2014-08-31
    相关资源
    最近更新 更多