ダブルクオートとシングルクオートの速度差は(ほぼ)ない

  • 4
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

Perlでは、パフォーマンスを重視するなら、シングルクオートを使うことが通説らしい(5.8時点。最近は知らない)。
それ以来、シングルクオートが文字列になる言語では基本的にシングルクオートを使うようにしている。
が、こんな記事を見つけてしまった。

Rubyのシングルクォートとダブルクォートは、実行速度には差が無い : /var/log/maeda.log
http://vividtone.seesaa.net/article/84396945.html

ダブルクオートの式展開はコンパイル時に解決されるらしい。
これを実際に検証したブログはないようだったので、検証してみた(Ruby 2.0 on OSX 10.10)。
irb上でRubyVM::InstructionSequence.compile(...).to_aを使うとバイトコードを表示できるので、これを読めば良いということになる。

検証に使う文字列はこれにした。

%q(x=5;puts "aaa #{x**3}")

irbに読ませると"x=5;puts \"aaa \#{x**3}\""となり、展開はされていないことがわかる。

irb> RubyVM::InstructionSequence.compile(%q(x=5;puts "aaa #{x**3}")).to_a
=> ["YARVInstructionSequence/SimpleDataFormat", 2, 0, 1, {:arg_size=>0, :local_size=>2, :stack_max=>4}, "<compiled>", "<compiled>", nil, 1, :top, [:x], 0, [], [1, [:trace, 1], [:putobject, 5], [:setlocal_OP__WC__0, 2], [:trace, 1], [:putself], [:putobject, "aaa "], [:getlocal_OP__WC__0, 2], [:putobject, 3], [:opt_send_simple, {:mid=>:**, :flag=>256, :orig_argc=>1, :blockptr=>nil}], [:tostring], [:concatstrings, 2], [:opt_send_simple, {:mid=>:puts, :flag=>264, :orig_argc=>1, :blockptr=>nil}], [:leave]]]

確かにコンパイル時点で式が展開されている。

念のため、シングルクオート版も見てみた。

irb> RubyVM::InstructionSequence.compile(%q(x=5;puts 'aaa '+(x**3).to_s)).to_a
=> ["YARVInstructionSequence/SimpleDataFormat", 2, 0, 1, {:arg_size=>0, :local_size=>2, :stack_max=>4}, "<compiled>", "<compiled>", nil, 1, :top, [:x], 0, [], [1, [:trace, 1], [:putobject, 5], [:setlocal_OP__WC__0, 2], [:trace, 1], [:putself], [:putstring, "aaa "], [:trace, 1], [:getlocal_OP__WC__0, 2], [:putobject, 3], [:opt_send_simple, {:mid=>:**, :flag=>256, :orig_argc=>1, :blockptr=>nil}], [:opt_send_simple, {:mid=>:to_s, :flag=>256, :orig_argc=>0, :blockptr=>nil}], [:opt_plus, {:mid=>:+, :flag=>256, :orig_argc=>1, :blockptr=>nil}], [:opt_send_simple, {:mid=>:puts, :flag=>264, :orig_argc=>1, :blockptr=>nil}], [:leave]]]

"aaa "が:putobjectから:putstringになっているので若干速くなっている可能性があるが、逆に命令数が増えてしまった。

式展開がない場合でも、実行時点では、:putobjectと:putstringの差しかない。
というわけで、ダブルクオートとシングルクオートの速度差は体感できるほどではないことがバイトコードから理解できた。

追伸:
あくまでYARVが対象なので、Ruby 1.8ではどのような扱いなのかは依然としてはっきりしないが、もはや気にする必要はないと思われる。