ベンチマーク時間:
require 'benchmark'
def amit_kumar_gupta(str_value)
str_value.index("APPLE") || str_value.index("DIAMOND") || str_value.index("GARLIC")
end
def priti(str_value)
%w(APPLE DIAMOND GARLIC).map{|i| str_value.index(i)}.compact[0]
end
def borodin(str_value)
/APPLE|DIAMOND|GARLIC/ =~ str_value
end
# I added a single anchor, based on knowledge of where the target would be, to
# show the difference an anchored search can make.
def borodin2(str_value)
str_value[/\b (?:APPLE|DIAMOND|GARLIC) \b\Z/x]
end
STRING = ('a'..'z').to_a.join * 100
APPLE_STRING = STRING + ' APPLE'
GARLIC_STRING = STRING + ' GARLIC'
N = 100_000
puts "RUBY_VERSION = #{ RUBY_VERSION }"
puts "N = #{N}"
Benchmark.bm(15) do |b|
b.report('amit apple') { N.times { amit_kumar_gupta(APPLE_STRING) } }
b.report('amit garlic') { N.times { amit_kumar_gupta(GARLIC_STRING) } }
b.report('priti apple') { N.times { priti(APPLE_STRING) } }
b.report('priti garlic') { N.times { priti(GARLIC_STRING) } }
b.report('borodin apple') { N.times { borodin(APPLE_STRING) } }
b.report('borodin garlic') { N.times { borodin(GARLIC_STRING) } }
b.report('borodin2 apple') { N.times { borodin2(APPLE_STRING) } }
b.report('borodin2 garlic') { N.times { borodin2(GARLIC_STRING) } }
end
1.9.3 の結果:
RUBY_VERSION = 1.9.3
N = 100000
user system total real
amit apple 0.540000 0.000000 0.540000 ( 0.539550)
amit garlic 1.560000 0.000000 1.560000 ( 1.567501)
priti apple 1.670000 0.000000 1.670000 ( 1.673736)
priti garlic 1.630000 0.000000 1.630000 ( 1.630529)
borodin apple 0.810000 0.010000 0.820000 ( 0.811853)
borodin garlic 0.810000 0.000000 0.810000 ( 0.817202)
borodin2 apple 0.220000 0.000000 0.220000 ( 0.223292)
borodin2 garlic 0.230000 0.000000 0.230000 ( 0.225041)
そして Ruby 2.0.0-p195:
RUBY_VERSION = 2.0.0
N = 100000
user system total real
amit apple 0.250000 0.000000 0.250000 ( 0.253446)
amit garlic 0.730000 0.000000 0.730000 ( 0.730139)
priti apple 0.820000 0.000000 0.820000 ( 0.825674)
priti garlic 0.820000 0.010000 0.830000 ( 0.821391)
borodin apple 2.230000 0.000000 2.230000 ( 2.240345)
borodin garlic 2.250000 0.010000 2.260000 ( 2.264021)
borodin2 apple 0.200000 0.000000 0.200000 ( 0.197568)
borodin2 garlic 0.190000 0.000000 0.190000 ( 0.197615)
そして、私たちは何を学びましたか? (ドロシー):
Amit のコードは||
、テストの短絡を利用しています。値index("APPLE")
が見つかった場合、それ以上のテストは必要なく、処理が停止します。これは、大規模なジョブの時間と CPU を大幅に節約します。「APPLE」と「GARLIC」を検索する必要があることの違いから、その効果を確認できます。最初のものは 1 回のテスト後に戻り、2 つ目は 3 回のテスト後に戻ります。
Priti's は、最初または 2 番目に答えが見つかったかどうかにかかわらず、すべてのテストを強制し、失敗した結果を破棄します。これは単純な試みであり、この種のコードを記述する方法ではありません。
Borodin のコードは、一連のさまざまな文字列全体を簡潔にテストする方法を示していますが、正規表現には多くのオーバーヘッドがあり、速度が低下する可能性があります。v2.0-p195 が 1.9.3 よりもずっと遅かったのは興味深いことです。それがバグなのか何なのかわかりませんが、重要です。コードでは、borodin2
部分文字列だけでなく単語全体をキャッチする方法も示しました。テキスト処理を行う場合、これは非常に重要であり、正規表現を使用していない場合は非常に難しくなります。あなたが完全な言葉を求めているなら、私の意見では正規表現が唯一の方法です。
テストを追加borodin2
し、単一の「行末」アンカーを追加して、文字列の構造に関するわずかな知識がいかに重要であるかを示しました。rindex
を代わりに使用するindex
と、最初の 4 つのテストも改善されます。また、いずれの場合でも、対象の文字列が検索文字列の先頭にあると、結果が低下します。その事前知識が重要です。データをスキャンして、何を探しているかを把握し、利用するパターンを見つけることができれば、コードをより高速に実行できます。
私の意見では、Amit のコードは短絡のため、最良の汎用コードです。Borodin のコードは拡張が最も簡単で、1.9.3 の方が高速ですが、2.0 では問題があります。個人的には、Ruby の別のリビジョンである YMMV で何が遅くなったのかを彼らが突き止めるだろうという前提で、borodin
またはを使用します。borodin2
私のマシンでは 2.0.0-p195 と 2.0.0-p247 の間にほとんど違いがないので、結果は表示しませんでした。そして、おそらくそれは私のパターンの欠陥であり、非常に賢い Ruby 関係者の 1 人がそれを修正するために協力してくれるでしょう。
Fruity を使用するようにコードを変更します。
require 'fruity'
def amit_kumar_gupta(str_value)
str_value.index("APPLE") || str_value.index("DIAMOND") || str_value.index("GARLIC")
end
def priti(str_value)
%w(APPLE DIAMOND GARLIC).map{|i| str_value.index(i)}.compact[0]
end
def borodin(str_value)
/APPLE|DIAMOND|GARLIC/ =~ str_value
end
# I added a single anchor, based on knowledge of where the target would be, to
# show the difference an anchored search can make.
def borodin2(str_value)
str_value[/\b (?:APPLE|DIAMOND|GARLIC) \b\Z/x]
end
STRING = ('a'..'z').to_a.join * 100
APPLE_STRING = STRING + ' APPLE'
GARLIC_STRING = STRING + ' GARLIC'
puts "RUBY_VERSION = #{ RUBY_VERSION }"
compare do
amit_apple { amit_kumar_gupta(APPLE_STRING) }
amit_garlic { amit_kumar_gupta(GARLIC_STRING) }
priti_apple { priti(APPLE_STRING) }
priti_garlic { priti(GARLIC_STRING) }
borodin_apple { borodin(APPLE_STRING) }
borodin_garlic { borodin(GARLIC_STRING) }
borodin2_apple { borodin2(APPLE_STRING) }
borodin2_garlic { borodin2(GARLIC_STRING) }
end
RUBY_VERSION = 2.1.0
Running each test 4096 times. Test will take about 6 seconds.
amit_apple is faster than amit_garlic by 2.6x ± 0.1
amit_garlic is faster than borodin2_garlic by 10.000000000000009% ± 1.0% (results differ: 2601 vs GARLIC)
borodin2_garlic is similar to borodin2_apple (results differ: GARLIC vs APPLE)
borodin2_apple is faster than priti_apple by 39.99999999999999% ± 1.0% (results differ: APPLE vs 2601)
priti_apple is similar to priti_garlic
priti_garlic is faster than borodin_apple by 10x ± 0.1
borodin_apple is faster than borodin_garlic by 2.0000000000000018% ± 1.0%
戻り値:
ルビー_バージョン = 2.1.0
各テストを 4096 回実行します。テストには約 6 秒かかります。
amit_apple は amit_garlic よりも 2.6x ± 0.1 高速です
amit_garlic は borodin2_garlic よりも 10.000000000000009% ± 1.0% 高速です (結果は GARLIC に対して 2601 と異なります)。
borodin2_garlic は borodin2_apple に似ています (結果は異なります: GARLIC と APPLE)
borodin2_apple は priti_apple よりも 39.99999999999999% ± 1.0% 高速です (結果は異なります: APPLE と 2601)
priti_apple は priti_garlic に似ています
priti_garlic は borodin_apple よりも 10x ± 0.1 高速です
borodin_apple は borodin_garlic よりも 2.0000000000000018% ± 1.0% 高速です