`String#==` は実行時間が最適化されているか?
昨日の記事で、 secure_compare
は String#==
とは異なり常に一定時間で処理が行われる、と書いた。
あらためて GitHub Developer から引用する。
Using a plain == operator is not advised. A method like secure_compare performs a "constant time" string comparison, which renders it safe from certain timing attacks against regular equality operators._1
しかし、本当に String#==
は実行時間が最適化されていて、入力次第で実行時間が異なるのだろうか?
String#==
のドキュメントには記述がなく、 Ruby 本体のソースを読もうにも上手く見当がつけられなかったので、愚直にベンチマークをとることにした。その結果が以下。
require 'benchmark' n = 1_000 chars = ['a'].cycle.take(n-1).join('') s1 = 'a' + chars s2 = 'b' + chars s3 = chars + 'b' t = 10_000 Benchmark.bm(12) do |x| x.report('at_the_front') do t.times { s1 == s2 } end x.report('at_the_end') do t.times { s1 == s3 } end end # user system total real # at_the_front 0.000444 0.000005 0.000449 ( 0.000442) # at_the_end 0.000990 0.000002 0.000992 ( 0.000991)
長さ1000の文字列について、先頭の文字が異なるケースと末尾の文字が異なるケースで比較している。それを10000回繰り返して、有意と言える差は出ている。わずかな差といえばわずかな差であるが、少なくとも表題の疑問には答えられているだろう。