プロが教える店舗&オフィスのセキュリティ対策術

皆様のお陰で、Rubyを実践的に理解し、仕事に活用しております。
ついでに、RubyとPerlの比較(処理時間)をしました。
同じデータを同じロジック作成されたそれぞれのスクリプトで処理しました。
スクリプトの作り方にも、問題はありますが、ざっくり、処理時間は、
Rubyは、Perlの倍の時間を要しているようです。
(Perlでは、2分、Rubyでは4分)
こんなもんなのでしょうか?
Rubyで、処理速度を上げる方法はあるのでしょうか?

A 回答 (5件)

プロファイルの結果の見方ですが詳しくは


Rubyリファレンスマニュアル - profile
http://www.ruby-lang.org/ja/man/?cmd=view;name=p …
を参照してください。
ProfilerではなくProfileですが、フォーマットは同一です。
Profilerのページはこちらに
Rubyリファレンスマニュアル - profiler
http://www.ruby-lang.org/ja/man/?cmd=view;name=p …


簡単には
time seconds seconds calls ms/call ms/call name
0.00 31.69 0.00 1 0.00 31688.00 #toplevel

一番下の行の左から二番目の数字が
プロファイリングした期間の所要時間です。
31.69
43.63
31.78
96.72 ← 計測間違い。正しくは60s前後の数字になります。

質問者さんのスクリプトでは正規表現の部分をいじっただけで
速度が大幅に変わったとのことでしたので、

正規表現について
get_profile("fixed pattern") { |l| l.each{ |x| /^\w+\s*$/ =~ x} }
get_profile("variable interpolation ") { |l| l.each{ |x| /#{patstr}/ =~ x} }
get_profile("variable interpolation with o flag") { |l| l.each{ |x| /#{patstr}/o =~ x} }
get_profile("Regexp object") { |l| l.each{ |x| pat.match(x)} }

・単純な固定パターン
・変数展開を含んだパターン
・変数展開にoフラグをつけたパターン
・正規表現オブジェクトを使用したパターン

について計測しています。
結果として

31.69 固定パターン
43.63 変数展開使用
31.73 oフラグつき変数展開
96.72 正規表現オブジェクト使用 (計測間違い。正しくは60s前後の数字になります)

となっており、変数展開は遅くなる要因であることが伺えます。
また、oフラグをつければ、変数展開を使っても
変数展開なしとほぼ同じ速度らしいと判断できます
#しかしなんで正規表現オブジェクトがこんなに遅いのだろう?

ただこの数字からはとても桁が変わるほどの影響が出るようには思えないのですが。

質問者さんがご自分のスクリプトのプロファイリングをしたいということでしたら、

一番単純なのは、オプションなどの処理を終えた
メインの処理の始まりのところで
Profiler__.start_profile

その処理が終わったところで
Profiler__.print_profile(STDOUT)
とすればよろしいのではないでしょうか。

プロファイリングしているときは当然ながら実行速度が
格段に落ちますのでご注意くださいませ。

それと
>宜しく、ご教授願います。
このような場合には「教示」を使うべきです。
    • good
    • 0
この回答へのお礼

sakusaker7さん、ありがとうございます。
また、新しい世界に踏み込んだような気がします。
一気に理解はできませんが、気長にやっていきます。
ありがとうございます。
また、言葉遣いの件、気をつけます。

お礼日時:2007/05/30 23:11

> こんなもんなのでしょうか?



現在のRubyインタプリタの実装では、
こんなもんと思います。参考URLでは、
短いサンプルプログラムのベンチマークによる比較
ではありますが、殆どのケースでRubyはPerlより
遅いことがわかります。

> Rubyで、処理速度を上げる方法はあるのでしょうか?

他の方が示されているように、プロファイルを取って
遅いところを高速化するのはRubyに限らず有効な手段ですし、
インタプリタ特有の高速化テクニックも存在するようですが、
いずれも手でプログラムを書き換える必要があります。

後はインタプリタの改良を待つしかないのですが、
現在開発中の Ruby 1.9
(「安定志向版」のRuby 1.9.1は今年12月リリース予定)
は、かなり高速なインタプリタが搭載されるので、それを
期待するのもいいかもしれません。

参考URL:http://shootout.alioth.debian.org/gp4/benchmark. …
    • good
    • 0
この回答へのお礼

jyufi_februaryさん、ありがとうございます。
Rubyがこんなに遅いとは、ちょっと意外でした。
しかし、Ruby 1.9に期待します。
新しい情報ありがとうございました。

お礼日時:2007/05/30 23:17

一般論で申し上げれば、Rubyは同様の処理をする他の言語(Perl、Pythonなど)


に比べると処理速度は遅い傾向にあります。

特に正規表現に関する部分は、Perlでは非常に手が入れられている部分で
色々高速化のための努力が払われています。

Rubyスクリプトを早く動作させるためのコツというものもあるにはありますが
今回はとりあえずそれは置いといて、

require 'profiler'

def get_profile(m)
puts m
testlines = <<EOS.split("\n")
xxxxxxxxxx
yyyyyyyyyy
zzzzzzzzzz
1111111111
aaaaaaaaa,
bbbbbbbbb
EOS

Profiler__.start_profile
1.upto(100000) do |i|
yield testlines
end

Profiler__.print_profile(STDOUT)
end

patstr = '^\w+\s*$'
pat = Regexp.new("#{patstr}")

get_profile("fixed pattern") { |l| l.each{ |x| /^\w+\s*$/ =~ x} }
get_profile("variable interpolation ") { |l| l.each{ |x| /#{patstr}/ =~ x} }
get_profile("variable interpolation with o flag") { |l| l.each{ |x| /#{patstr}/o =~ x} }
get_profile("Regexp object") { |l| l.each{ |x| pat.match(x)} }

こんな感じに簡単にプロファイリングしてみた結果が以下です。

fixed pattern
% cumulative self self total
time seconds seconds calls ms/call ms/call name
73.31 23.23 23.23 100000 0.23 0.23 Array#each
26.69 31.69 8.46 1 8457.00 31688.00 Integer#upto
0.00 31.69 0.00 1 0.00 31688.00 #toplevel
variable interpolation
% cumulative self self total
time seconds seconds calls ms/call ms/call name
81.41 35.52 35.52 100000 0.36 0.36 Array#each
18.59 43.63 8.11 1 8109.00 43625.00 Integer#upto
0.00 43.63 0.00 1 0.00 43625.00 #toplevel
variable interpolation with o flag
% cumulative self self total
time seconds seconds calls ms/call ms/call name
63.22 20.09 20.09 100000 0.20 0.20 Array#each
36.78 31.78 11.69 1 11688.00 31782.00 Integer#upto
0.00 31.78 0.00 1 0.00 31782.00 #toplevel
Regexp object
% cumulative self self total
time seconds seconds calls ms/call ms/call name
56.56 54.71 54.71 100000 0.55 0.85 Array#each
31.11 84.80 30.09 600000 0.05 0.05 Regexp#match
12.32 96.72 11.92 1 11920.00 96719.00 Integer#upto
0.00 96.72 0.00 1 0.00 96719.00 #toplevel

一応一般的な傾向は読み取れるのではないかと思います。
質問者さんが#2の補足で述べられた十倍強の比率には
なりませんが、
ナイーブに #{}による変数展開を使った正規表現マッチングは
時間が掛かっています。

この回答への補足

sakusaker7さん、ありがとうございます。
示してくださったサンプルは、小生の環境で、うまく動きました。
しかしながら、profiler、スクリプトを理解しようと努めましたが、まだよく分かっておりません。
Rubyリファレンスマニュアルでは、"profile は各メソッドの実行時間に関する統計を出力”とあります。

require 'profiler' ---ライブラリ呼び出し

def get_profile(m) -------関数定義

Profiler__.start_profile--ライブラリ「profiler」に対してスタート指示

1.upto(100000) do |i| -----よく分かりません

Profiler__.print_profile(STDOUT) ---ライブラリ「profiler」への指示

主たる検証内容------------------------------------------------------
get_profile("fixed pattern") { |l| l.each{ |x| /^\w+\s*$/ =~ x} }
get_profile("variable interpolation ") { |l| l.each{ |x| /#{patstr}/ =~ x} }
get_profile("variable interpolation with o flag") { |l| l.each{ |x| /#{patstr}/o =~ x} }
get_profile("Regexp object") { |l| l.each{ |x| pat.match(x)} }
主たる検証内容------------------------------------------------------

仮に小生のスクリプトを使って、実行時間に関して統計を取ろうとした場合、どのようにすれば良いですか?

それと、具体的に、出力をどのように、理解すればよいのか、解説していただけないでしょうか?
# % cumulative self self total
# time seconds seconds calls ms/call ms/call name
# 60.49 122.90 122.90 100000 1.23 1.76 Array#each
# 25.91 175.56 52.66 600000 0.09 0.09 Regexp#match
# 13.60 203.19 27.64 1 27636.00 203193.00 Integer#upto
# 0.00 203.19 0.00 1 0.00 203193.00 #toplevel

処理時間は、203.19秒。Array#eachが全体の所要時間の60.49%を占めており、その時間は203.19秒である。
Array#eachは、呼出回数が、100000であったので、1回当たりは、1.23msecである。
total ms/callがよくわかりません。
ここから、何を掴めばよいのか、まだよく分かりません。

誠に、申し訳ありませんが、宜しく、ご教授願います。

補足日時:2007/05/30 00:25
    • good
    • 0

Perl もインタプリタです。



まず、どこで時間を喰っているのかプロファイルする必要があります。
単純に言語比較はできないでしょう。

この回答への補足

shuujin01さん、ありがとうございます。

>まず、どこで時間を喰っているのかプロファイルする必要があります。
以下のような、内容で足りるでしょうか?

対象フォルダに存在するファイル数:45個
ファイルサイズ:500Kbyteから5MByte/file
対象行総数-----------------3840000行
処理内容-------------------テキスト処理

小生、最初に、Perlにて、スクリプトを組みました。
次に、アルゴリズムはそのままに、RUBYで書き換えました。

経験的に、RUBYでは、正規表現の中に、変数を持ち込むと、処理時間が長くなるのに気がついております。
そこで、意図的に、これを実施してみました。
(/^ABC\s*$/=~text) && (myFlabA==1) && (myFlabA=0)
この部分(スクリプトの中に6箇所)を、次のように書き換えました。

myITEM="ABC"
(/^#{myITEM}\s*$/=~text)

0から、6箇所すべてを置き換えて、処理時間を記録しました。
結果は、以下の通りです。
置換数--処理時間
0 ---0:04:17 (4分17秒)
1 ---0:09:14
2 ---0:14:29
3 ---0:20:45
4 ---0:28:16
5 ---0:45:30
6 ---0:50:00 (50分00秒)

この実験から、基本的に、スクリプトのアルゴリズムは、関係ないと考えます。
むしろ、RUBYであるが故の、組み方の問題、例えば、上記のような、
正規表現の中に、変数を持ち込む際には、なるべく、数を減らすか、パターンをイミーディエートで記述する、ということであろうと、考えます。

小生の理解したことは、ここまでです。
宜しく、サジェスチョンをお願いいたします。

補足日時:2007/05/27 20:02
    • good
    • 0

Rubyはインタプリタ言語だったと記憶しています。


故に実行形式のPerlより処理速度は落ちます。
処理速度を上げるなら、アルゴリズムを変えるしかないでしょう。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!