2015-09-17 15 views
9

Rubyのアルゴリズムの基本的な問題を解決し、パフォーマンスをテストしようとしています。Rubyの各whileループのパフォーマンス

は、念のために、アルゴリズムは、20 ここに1から番号のすべてで割り切れる最小の正の数を見つけることを目的コードです:バージョン間で、自分のコンピュータ上で

def remainder(number) # with while 
    divisor = 2 
    while divisor < 21 
    return false unless number % divisor == 0 
    divisor += 1 
    end 
    true 
end 

def remainder(number) # with each 
    (2..20).each do |divisor| 
    return false unless number % divisor == 0 
    end 
    true 
end 

number = 180_000_000 
while number < 10_000_000_000 
    if remainder number 
    puts "#{number}" 
    break 
    end 
    number += 1 
end 

Rubyは約10秒かかっており、バージョンごとに70〜80秒かかることがあります。コードはまったく同じことを行い、同じ結果をもたらします。なぜそのようなパフォーマンスの違いがありますか?

答えて

5

コストをによって追加されると思われる:ベンチマーク

あるここ each

  1. レンジオブジェクトの列挙子の作成(2..20)
  2. ブロックの呼び出し
    require 'benchmark' 
    
    c = 100_000 
    Benchmark.bm(7) do |x| 
        x.report("range - 1 :") { c.times { (2..20) } } 
        x.report("range - 2 :") { c.times { (2..20).each } } 
        x.report("range - 3 :") { c.times { (2..20).each { |x| x } } } 
    end 
    

    上記のサンプル出力は、

    012図から分かるように
       user  system  total  real 
    range - 1 : 0.000000 0.000000 0.000000 ( 0.006004) 
    range - 2 : 0.031000 0.000000 0.031000 ( 0.026017) 
    range - 3 : 0.125000 0.000000 0.125000 ( 0.122081) 
    [Finished in 0.4s] 
    

    、Rangeオブジェクトの作成は問題ではないが、それの列挙子を作成する時間を加算し、そのイテレータにブロックを渡すと、いくつかのコードを実行し、さらにコストを追加します。

    これに対して、whileのループ実装では、プリミティブ操作が行われています。したがって、より速いです。

    それは多かれ少なかれ同等each実装

+3

また、Rubyコードの数があまり多いわけではないので、 'number%divisor == 0'以外の場合は' return false 'のコストに対するこれらのsmall-ishコストを比較しています。 Rubyでは、Rangesで列挙子をインスタンス化したり、コードを構造化するためのブロックベースのメソッドを使用したりしないようにする必要があります。まれな状況では、大きな時間差が生じることがあります –

1

eachは方法であり、それはあなたwhileループはありません同じことを(Cで)forループを使用して、Cでwhileを使用してを実施しています。内部的にはカウンタを保持する必要があります。2に初期化し、20までインクリメントしてください。whileのバージョンで行う必要があります。しかし、eachバージョンは、関数(ブロック)を作成し、eachメソッドに送信し、eachメソッドの実装内のforループのすべての繰り返しで呼び出します。このすべては、コードを遅くするコンピュータからの余分な作業を必要とします。

+1

にあると 'each'バージョンが作成され、ゴミは'(2..20) ''範囲を収集して、forループはeachほどひどく実行されますのでご注意くださいnumber ... times ... – spickermann

+1

#範囲全体が 'for'ループで実装されています - http://ruby-doc.org/core-2.2.3/Range.html#method-i-each – Anthony

+0

@NeilSlater - 私は同じことを考えたが、何かをしていない。何かしている間、エンド '相当? – Anthony