[ruby-list:49457] Re: 【質問】定数の文字列展開について

From: Kazuhiro Shibutani <arikui.ruby@...>
Date: 2013-06-08 17:51:07 UTC
List: ruby-list #49457
ありくいという者です。

> 定数の文字列を正規表現の中で展開するタイミングは,Ruby
> スクリプトのコンパイル時ではなくて,実行時なのでしょうか?

その通りです。
Rubyはとても動的な言語なので、実行してみるまでほとんど式の値と
いうのはわかりません。oオプションは最初の一回の評価をキャッシュ
するような動作をするので、一回は式展開します。

 正規表現リテラル - Ruby 2.0.0 リファレンスマニュアル
 http://doc.ruby-lang.org/ja/2.0.0/doc/spec=2fliteral.html#regexp

対して、正規表現リテラルはスクリプトのコンパイル時に解決できるので
(1)(2)と(4)で実行コストに差が出るのは自然なのです。
(1)(2)は実行のたびにRegexpオブジェクトを生成しているわけではありません。

> また,予め正規表現をコンパイルしておいた case(5), (6) よりも,
> 正規表現をリテラルのままにしてある case(1), (2)
> のほうが速いのも腑に落ちません.

これらも、コンパイル時に解決される(1)(2)が一番実行コストが安いことによる
ものです。
(あと(5)(6)は微妙にn回定数参照しているオーバーヘッドが地味に効いているような
気がします)




2013年6月8日 9:38 俊(とし) <toshio.otaguro@gmail.com>:

> 非常に初歩的な質問で申し訳ないのですが,定数の文字列を正規表現の中で展開するタイミングは,Ruby
> スクリプトのコンパイル時ではなくて,実行時なのでしょうか?
>
> # --------------------
> n = 1000000
> line0 = "abc | 123"
> C0 = '\s\|\s'
> R0 = Regexp.new(/\s\|\s/)
> R1 = Regexp.new(C0)
>
> tstart = Time.now()
> n.times { /\s\|\s/ =~ line0 }
> tstop = Time.now()
> $stderr.print "case(1) ", (tstop - tstart), "\n"
>
> tstart = Time.now()
> n.times { /\s\|\s/o =~ line0 }
> tstop = Time.now()
> $stderr.print "case(2) ", (tstop - tstart), "\n"
>
> tstart = Time.now()
> n.times { /#{C0}/ =~ line0 }
> tstop = Time.now()
> $stderr.print "case(3) ", (tstop - tstart), "\n"
>
> tstart = Time.now()
> n.times { /#{C0}/o =~ line0 }
> tstop = Time.now()
> $stderr.print "case(4) ", (tstop - tstart), "\n"
>
> tstart = Time.now()
> n.times { R0 =~ line0 }
> tstop = Time.now()
> $stderr.print "case(5) ", (tstop - tstart), "\n"
>
> tstart = Time.now()
> n.times { R1 =~ line0 }
> tstop = Time.now()
> $stderr.print "case(6) ", (tstop - tstart), "\n"
> # --------------------
>
> 上記のサンプルプログラムをRuby-2.0.0p208 (rev. 41155) で走らせると,結果は以下のようになります.
>
> case(1) 0.311638805
> case(2) 0.312117764
> case(3) 8.188489523
> case(4) 0.396936021
> case(5) 0.330860272
> case(6) 0.330536675
>
> ここで疑問は,case(3)
> が異常に遅いのは,実行時に毎回,定数であっても文字列を展開しているのだろうと推測しますが,ちょっと腑に落ちないのは,case(4) で o
> オプションを付けても case(1), (2) よりもかなり遅いという点です.
>
> また,予め正規表現をコンパイルしておいた case(5), (6) よりも,正規表現をリテラルのままにしてある case(1), (2)
> のほうが速いのも腑に落ちません.
>
> ちなみに Ruby-1.9.3p194 (rev. 35410) で走らせると以下のような結果になります.特に,case(3)
> が上記よりは速いのが目立ちますが,これは正規表現エンジンが異なるからでしょうか?
>
> case(1) 0.30897303
> case(2) 0.308756529
> case(3) 3.997449237
> case(4) 0.356132962
> case(5) 0.336724425
> case(6) 0.33666136
>
> ご教示いただければ幸いです.
> --
> 俊(とし)
>
> <http://griffin.cocolog-nifty.com/lakesidedairy/>
>

In This Thread