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コードは、整数を合計する2つの方法を比較しています。驚いたことに、よりエレガントな注入または削減アプローチは、他のアプローチよりも優れています。なぜそうなのですか?なぜ人々は非効率的な注入または削減をわざわざ使用するのですか?エレガントだから?

PS:すべての刺激的な答えをありがとう。私の意図は、違いをもたらす舞台裏で何が起こっているのかを尋ねることでした。

4

6 に答える 6

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)
% 

より良い数学は常により速いです:)

于 2011-10-06T20:45:31.960 に答える
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)
于 2011-10-06T20:34:56.680 に答える
3

代わりに次を試してください。

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

個人的に私は優雅さを求めています。もしそれが乱雑にならない限り、単一のラインインジェクトがそれぞれ3つのラインを置き換えることができるなら、私はインジェクトで行きます。

于 2011-10-06T20:22:45.740 に答える
3

@derpは正しいです。次回は次のようにベンチマークモジュールを使用することをお勧めします。

#!/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
于 2011-10-06T20:24:43.587 に答える
2

以前の回答のほとんどまたはすべてが、おそらく最新のメジャーバージョンのruby(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)

ただし、読みやすさとメンテナンスがより重要であることに完全に同意します。

于 2011-10-07T05:03:10.523 に答える
1

Rubyは主にパフォーマンスに関するものではありません。パフォーマンスが必要な場合は、そのために設計された他の言語があります。

Rubyは、エレガントなコードを書くことの喜びです:)

于 2011-10-06T20:34:58.270 に答える