2011-10-06 38 views
3
b1 = Time.now 
puts (1..100000).inject(0) { |x, y| x + y } 
a1 = Time.now 
puts "Time for inject: #{a1 - b1}" 

b2 = Time.now 
sum = 0 
(1..100000).each do |value| 
    sum += value 
end 
puts sum 
a2 = Time.now 
puts "Time for each: #{a2 - b2}" 

上面的Ruby代碼比較了總結整數的兩種方式。令我驚訝的是,更優雅的注入減少方法是優於其他。爲什麼會這樣?爲什麼人們打擾使用低效注入減少?僅僅因爲它很優雅? PS:感謝所有鼓舞人心的答案。我的意圖是詢問幕後發生的事情是什麼導致了這些差異。紅寶石地圖/降低功能必要的效率?

+1

如果你在你做的每件事情中都計算納秒,你就沒有時間去做任何有效的事情。另請參見「過早優化」(不要使用刪節版本 - 正如完整的引用正確地指出的那樣,在某些情況下,像這樣的事情確實很重要)。 – delnan

+0

謝謝。非常周到的意見! –

回答

6

我會用一些數學走在這種情況下:

require "benchmark" 

N = 5_000_000 

Benchmark.bmbm do |bm| 
    bm.report "inject 1" do 
    (1..N).inject(0) { |x, y| x + y } 
    end 

    bm.report "inject 2" do 
    (1..N).inject(:+) 
    end 

    bm.report "each" do 
    sum = 0 
    (1..N).each do |value| 
     sum += value 
    end 
    end 

    bm.report "sum of finite arithmetic progression" do 
    ((1 + N) * N)/2 
    end 
end 

,其結果是:

% ruby sum.rb 
Rehearsal ------------------------------------------------------------------------ 
inject 1        0.500000 0.000000 0.500000 ( 0.507497) 
inject 2        0.320000 0.000000 0.320000 ( 0.322675) 
each         0.370000 0.000000 0.370000 ( 0.380504) 
sum of finite arithmetic progression 0.000000 0.000000 0.000000 ( 0.000005) 
--------------------------------------------------------------- total: 1.190000sec 

              user  system  total  real 
inject 1        0.500000 0.000000 0.500000 ( 0.507697) 
inject 2        0.320000 0.000000 0.320000 ( 0.322323) 
each         0.370000 0.000000 0.370000 ( 0.380307) 
sum of finite arithmetic progression 0.000000 0.000000 0.000000 ( 0.000004) 
% 

一個更好的數學總是更快:)

+1

最後一個很特別。什麼是靈感!謝謝。 –

3

嘗試,而不是執行以下操作:

puts (1..100000).inject(:+) 

個人而言,我去的優雅,如果單行注入可以分別只要更換一個三線的爲它不」變得混亂我會用注射去。

+0

謝謝。我剛試過這個。事情變得越來越有趣:這一個勝過我的兩個!那裏發生了什麼? –

+0

表示方法「+」的符號正在發送並應用到元素中。可以用map,'['a','b','c']來做類似**的事情。map(&:upcase)'會返回'['A','B','C 「]'。另一點我沒有提到,當你沒有通過注入起始值時,它使用第一個元素,所以基本上''().inject(0){}'上的0對於這種情況沒有必要。 – derp

+0

真是一課!再次感謝。 –

3

@derp是對的。我建議你使用Benchmark模塊下一次這樣的:

#!/usr/bin/env ruby 

require "benchmark" 

Benchmark.bm do |x| 
    x.report { (1..10000000).inject(:+) } 
    x.report { sum = 0; (1..10000000).each { |value| sum += value } } 
end 
+0

謝謝。不知道基準模塊,這對於分析代碼似乎非常方便。 –

5

是,代碼的可讀性比微的優化更爲重要。即使採取數百萬元的總和,差異也幾乎不明顯。此外,兩種方法都是O(n),所以隨着元素數量的增加,兩者都不會顯着優於另一種。

正如其他人所指出的,inject(:+)還是有點快。即使不是,選擇一個最簡單的眼睛,不要擔心性能上的微小差異。這可能不會成爲您的應用程序的瓶頸。

require "benchmark" 

N = 5_000_000 

Benchmark.bmbm do |bm| 
    bm.report "inject 1" do 
    (1..N).inject(0) { |x, y| x + y } 
    end 

    bm.report "inject 2" do 
    (1..N).inject(:+) 
    end 

    bm.report "each" do 
    sum = 0 
    (1..N).each do |value| 
     sum += value 
    end 
    end 
end 

結果:

   user  system  total  real 
inject 1 0.610000 0.000000 0.610000 ( 0.613080) 
inject 2 0.370000 0.000000 0.370000 ( 0.370892) 
each  0.570000 0.000000 0.570000 ( 0.568266) 
+0

謝謝!這非常有幫助。 –

+1

贏家是...'(1 + N)* N/2' – steenslag

+1

@steenslag,很好!儘管如果'Range#each'已被重新定義,它會失敗! ;) – molf

1

紅寶石大多不是表演。如果你想要表演,還有其他語言是爲此而設計的。

紅寶石是所有的樂趣寫優雅的代碼:)

+0

是的。所以Matz剛剛發明了Ruby,好玩嗎? –

+1

@TerryLiYifeng,是的,沒錯! – molf

+1

@TerryLiYifeng我想是這樣:) Ruby對網站有好處,因爲它非常方便,非常優雅,而且非常靈活。即使它是快速解釋的語言,快速並不是他的屬性之一。 –

2

有趣的是,大部分或所有前面的回答ers可能會採用最新的主要版本(1.9)。在1.8.7這種差異更加明顯:

$ ruby -v 
ruby 1.8.7 (2011-02-18 patchlevel 334) [i686-darwin10.6.0], MBARI 0x6770, Ruby Enterprise Edition 2011.03 
$ ruby bench.rb 

Rehearsal ------------------------------------------------------------------------ 
inject 1        3.910000 0.010000 3.920000 ( 3.932388) 
inject 2        0.660000 0.000000 0.660000 ( 0.662330) 
each         1.120000 0.010000 1.130000 ( 1.126276) 
sum of finite arithmetic progression 0.000000 0.000000 0.000000 ( 0.000009) 
--------------------------------------------------------------- total: 5.710000sec 

              user  system  total  real 
inject 1        3.930000 0.010000 3.940000 ( 3.956084) 
inject 2        0.680000 0.000000 0.680000 ( 0.685073) 
each         1.110000 0.000000 1.110000 ( 1.109675) 
sum of finite arithmetic progression 0.000000 0.000000 0.000000 ( 0.000009) 

可讀性&維護絕對同意是更重要的,雖然。

+0

+1不錯的補充!謝謝。 –