-2

過去何日にもわたって、ルビーでコードを書いている間、線形コードは反復よりも高速で好ましいのかという疑問があります。

例を挙げましょう。2つの異なる方法で記述された同じ機能のコードブロックがあります。

方法1:

['dog', 'cat', 'tiger'].each do |pet_name|
  puts "I have many pets, one of them is #{pet_name}."
end

方法2:

puts "I have many pets, one of them is dog."
puts "I have many pets, one of them is cat."
puts "I have many pets, one of them is tiger."

だから、どちらがより良くて好ましいのか知りたいですか?私の見解によると、2番目のものは時間とメモリが少なくて済むと思います。でも確認したいです。

4

6 に答える 6

3

シーケンシャルロジックは高速ですが(フォールドの下のベンチマークを参照)、ほとんど問題になりません。より明確で保守しやすいコードを常に選択する必要があります。実証されたニーズのみが、プログラマーの最適化を中止し、マシンの最適化を開始する必要があります。実証されたということは、測定されたことを意味します-あなたはそれを実行し、それが遅すぎることに気づきました。

2番目の例は、 DRY(Do n't Repeat Yourself)の原則に違反しており、マイナーなメンテナンスの問題です。


require 'benchmark'

LOOPS = 100000

Benchmark.bm(10) do |x|
  x.report('iteration') do
    LOOPS.times do
      ['dog', 'cat', 'tiger'].each do |pet_name|
        "I have many pets, one of them is #{pet_name}."
      end
    end
  end
  x.report('sequence') do
    LOOPS.times do
      "I have many pets, one of them is dog."
      "I have many pets, one of them is cat."
      "I have many pets, one of them is tiger."
    end
  end
end

# =>                  user     system      total        real
# => iteration    0.200000   0.000000   0.200000 (  0.202054)
# => sequence     0.010000   0.000000   0.010000 (  0.012195)
于 2012-08-29T11:11:35.723 に答える
1

どちらの場合も、実際のRubyコードの実行に費やされる時間は、テキストを画面に印刷するのにかかる時間によって完全に支配されます。注意:コンソールの出力は遅いです。本当に遅い。痛々しいほど遅い。

どちらの場合も、コードは同じ量のテキスト(実際には同じテキスト)を画面に出力するため、存在する場合も存在しない場合もあるわずかなパフォーマンスの違いは、ノイズによって失われます。

2つ目は時間とメモリが少なくて済むと思います。

考えないでください。見て。

ここにクレイジーなアイデアがあります。どちらがより速く実行されるかを知りたい場合は、それらを実行して、どれがより速く実行されるかを確認してください。

于 2012-08-29T10:56:41.133 に答える
0

厳密に言えば、はい、反復にはオーバーヘッドが伴います。使用する言語はすべてあります(ただし、これを減らすためにコンパイラのトリックを使用するものもあります)。コードの最初のバージョンは、反復のコストと定義した配列の構築のコストのために、ごくわずかな量の速度で実行されます。また、文字列の構築により、おそらくもう1つの小さなコストが追加されます。

そうは言っても、それはあなたが気付くのに非常に気を配る必要がある、あるいはこれのいずれかを気にする必要があるような小さな違いです。それはごくわずかです。自分でベンチマークを試してみてください。大きな違いに気付くことはありません。

なんらかの方法でそのような10,000行を書く準備ができていませんね。特に重要なコードの場合、反復は非常にクリーンに見え、読みやすさとクリーンなコードの観点からは多くの場合好ましいことがわかります。言うまでもなく、それはもっとドライです。

于 2012-08-29T10:56:33.500 に答える
0

関数の呼び出し、配列の作成、またはループの作成には常にコストがかかります。ただし、これがプログラミング言語の目的であるため、質問に答えてください。そうです、2番目のコードはより高速で、おそらくナノ秒です。しかし、最初のコードはより一般的であり、いつ新しいペットを購入するかはわかりません。それはもっと便利です、多分誰かがあなたに彼らのペットのリストを与えるでしょう、そしてあなたは彼らについて話したいと思うでしょう?一般的に言えば、2番目のコードは目立たないほど高速ですが、最初のコードの方が優れており、望ましいです。

于 2012-08-29T10:58:21.880 に答える
0

あなたの例は非常に単純化されており、現実の世界では起こりそうにないことを私は理解していますが、文字通りそれを取る:

最初の例では中間オブジェクト(文字列と配列)が作成されるため、実際にはより多くのメモリが必要になると言えます。ただし、これらのオブジェクトは後でガベージコレクションされるため、メモリを取り戻すことができます。(シンボルはガベージコレクションされないため、シンボルの配列を定義した場合は当てはまりません)。

また、各反復中に配列からオブジェクトを内部的にフェッチする必要がないため、より高速です。しかし、明らかに目立たない場合は違いを考慮に入れるべきではありません。ここで考慮すべきことは読みやすさです。

パフォーマンスがおかしい場合は、引数を括弧なしでメソッドを定義する必要があります。これにより、Rubyインタープリターによって作成される解析ツリーが小さくなるためです。

# slower
def meth(arg)
end

# faster
def meth arg
end

しかし、それを正当な理由と考えるのはもちろんばかげています。

編集:良いRubyスタイルガイドを探しているなら、これをチェックしてください:https ://github.com/bbatsov/ruby-style-guide

于 2012-08-29T11:03:34.790 に答える
0

これらの2つのオプションのいずれかが明らかに優れていて、したがって望ましい場合、言語は両方のオプションを提供しません。いつものように、それは状況に依存します。決定するために尋ねるべき質問には、

  • どのソリューションがより読みやすいですか?(習慣的なRubyプログラマーにとって、最初のものはそうです。)読みやすいほど良いです。
  • どのソリューションが速いですか?(これは測定することによってのみ決定できます。現実的な例を使用するように注意してください。3匹の動物だけの時間差は確実に測定できない場合があります。)速いほど良いです。
  • より慣用的なバージョンを「展開」することで、どのくらいの重複が導入されますか?(この場合、それほど多くはありません-puts文字列リテラルの一部です。)導入する重複が少ないほど、優れています。

ご覧のとおり、答えは互いに矛盾しているため、決定のコンテキストを理解し、要素を正しく比較検討して、全体として最適なものを見つける必要があります。

于 2012-08-29T11:01:20.597 に答える