2010-10-28 60 views
4

我有興趣比較ruby速度與python,所以我採取了最簡單的遞歸計算,即打印fibonacci sequance。這個python代碼有什麼問題,爲什麼它比ruby運行速度慢?

這是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 

這裏是Ruby代碼

#!/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 

這就是紅寶石,現在python2 .7給出

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

這是怎麼回事?

+2

我只是想指出的是,迭代計算,這將是一個獨立於語言的感覺快很多。在這裏使用遞歸會導致一次又一次地計算相同的值。 – 2010-10-28 19:32:54

+10

我不會列出答案,因爲我不知道確切的原因,但它可能是ruby編譯器有一些優化,Python不支持。天真的fib函數使用遞歸創建了一些語言無法很好處理的巨大調用堆棧。特別是,該語言通常必須實現tail-call遞歸優化,以便在更大的遞歸量下正常處理這種情況並且不會發生堆棧溢出。 – CodexArcanum 2010-10-28 19:34:46

+1

我同意CodexArcanum。這可能是密切相關:http://stackoverflow.com/questions/824562/does-ruby-perform-tail-call-optimization – duffymo 2010-10-28 19:36:45

回答

7

蟒蛇的遞歸效率更好的比較是事業這個開銷。有關更多詳細信息,請參見this article。以上解決這個迭代的解決方案對python更好,因爲它們不會導致函數調用開銷遞歸。我對ruby的假設是,它明顯優化了代碼,而python卻沒有。再一次,該文章使用幾乎相同的fib函數詳細說明了這一點。

+0

我喜歡你鏈接的那篇文章的評論。這確實揭示了在python中使用遞歸函數調用。 – rapadura 2010-10-29 08:54:40

2

所以對於這段代碼,Python比Ruby慢兩倍以上。可能對於其他代碼,Python將比Ruby更快。

您的fib()實現具有指數運行時間。這很容易通過使用循環來避免。 Python示例:

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

問題不在於如何編寫高效的fib()實現。問題是爲什麼在Python中創建巨大的調用堆棧比在Ruby中成本更高(如果是)。 – jfs 2010-10-28 23:04:13

+0

我的主要觀點實際上應該是觀察到的差異很小 - 這只是一個因素,這根本不奇怪。我再次閱讀我的文章,我認爲其他人的評論是更好的,但我會把它留在那裏:) – 2010-10-29 13:43:17

2

您計算fibonacci序列中前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 

然後,您可以使用此代碼打印所有Fibonacci數高達35:

for f in fibo_generator(35): 
    print f 

這是迄今爲止在Python中實現斐波那契序列的最有效的方式,以及最通用的。

+4

我不想要最高效的編程語言X,我想知道爲什麼幾乎精確的Python和紅寶石程序運行在非常不同時間框架。紅寶石版本是否優化了我背後的代碼?雖然我們在這裏,但我認爲備忘會加速它的發展。 – rapadura 2010-10-28 20:05:11

+0

查看THC4k的答案爲什麼這個測試沒有任何意義。這並不意味着Python比Ruby慢,因爲你的應用程序沒有多大意義。爲什麼你會用任何語言做一些效率低下的事情?當你發揮其優勢時,Python是最快的,就像Ruby一樣。 – 2010-10-28 20:07:55

2

我很感興趣,比較紅寶石 速度VS蟒蛇

微基準測試是一個非常糟糕的方式來比較的語言,你都掌握了特別了。如果你想有任何真實世界的意思,那麼你需要把大量的精力投入到它的基準 - 或者你google for "language shootout"

這裏是Python and Ruby

+1

爲什麼這是比較語言的不好方法?與python中幾乎相同的代碼相比,ruby的速度是什麼原因?我知道可以使用生成器,memoization等來給出序列更好的時間...但是我感興趣的是 - 爲什麼這個相同代碼的巨大差異? – rapadura 2010-10-28 20:07:28

+0

@AntonioP:因爲只有初學者編寫這樣的代碼。您的基準測試只會告訴您「這個不好的Python程序比那個糟糕的Ruby程序要慢」。只有比較最快的實現纔是有意義的,而不是使用相同的代碼。 – 2010-10-28 20:22:10

+5

我必須同時同意和不同意。確實,比較不好的節目是沒有幫助的。不過,我不同意你應該比較最快的實現。我認爲你應該比較最好的設計實現。編譯器編寫者的工作是確保設計得最好的實現也是最快的,但如果它*不是*,那麼你不應該優化代碼,你應該修復編譯器。 – 2010-10-28 22:27:40

2

這裏的一些數字進行比較:

Python2.7 
9.67 user 0.09 system 0:09.78 elapsed 99%CPU (0avgtext+0avgdata 16560maxresident)k 
0inputs+0outputs (0major+1169minor)pagefaults 0swaps 

ruby 1.8.7 (2010-06-23 patchlevel 299) [x86_64-linux] 
28.37 user 0.35 system 0:28.78 elapsed 99% CPU (0avgtext+0avgdata 9200maxresident)k 
1896inputs+0outputs (9major+656minor)pagefaults 0swaps 

ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux] 
6.21 user 0.08 system 0:06.36 elapsed 98% CPU (0avgtext+0avgdata 14160maxresident)k 
4416inputs+0outputs (16major+953minor)pagefaults 0swaps 

Python是三倍比ruby1.8的快比ruby1.9慢了30%。1代碼提供。

其他Python版本進行比較:

2.4.6 took 10.30 seconds 

2.5.5 took 9.93 seconds 

2.6.6 took 9.22 seconds 

2.7 took 9.35 seconds 

3.0.1 took 11.67 seconds 

3.1.2 took 11.35 seconds 

3.2a3+ (py3k:85895, Oct 29 2010, 01:41:57) 
[GCC 4.4.5] took 13.09 seconds 

2.5.2 (77963, Oct 15 2010, 02:00:43) 
[PyPy 1.3.0] took 21.26 seconds 

2.5.1 (Release_2_5_1:6813, Sep 26 2009, 13:47:54) 
[OpenJDK 64-Bit Server VM (Sun Microsystems Inc.)] took 8.81 seconds