2011-10-06 50 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不错的补充!谢谢。 –