v8のlastIndexOfが(相対的に)遅い

  • 投稿日:
  • by
  • カテゴリ:

最近honoにコントリビュートをしていて、正規表現の結果からの文字列を探索する際にindexOf()の代わりにlastIndexOf()を使ったら最適化できないだろうかと考えたりしていたのですが、だめでした。これはその際に調べたことのメモです。

まず最初に、1000個のcaptureを返す正規表現の結果から500番目を探すパターンでベンチマークをとってみます。

どのバージョンでもindexOf()が文字通り桁違いに速く、lastIndexOf()はforやwhileにすら負けて最下位になっています。(ただindexOf()を使った場合にも変数へのアサインを挟んだだけでここまでの差にはならなかったりするので、どれも基本的には速く、ちょっとした条件の変化で結果が変わったりする程度のものでもあるとは思います。)単純に1つの空文字列を探索する場合にはindexOf()を使うのがよさそうです。

v8のコードを見てみたところ、indexOfの方はc++のコードで、lastIndexOfはマクロのコードで書かれていたので、その辺りで違いが出ているのかもしれません。

次に、以下のように「最大で2つの連続した空文字列が返ってくる match() の結果から、一番最後の空文字列の位置を取得する(captureは2000個)」というケースでのベンチマークをとってみます。

これはバージョンごとの違いが大きく、v16だと「indexOf()とforループがほぼ同じ性能」で、v17だと「indexOf()が最速で2倍近い性能」、そしてv18(pre)だと「forループが最速」となりました。

結論のようなものはなかなか難しいですが。

  • 正規表現の結果から最初の1つの文字列を探す場合にはArray.prototype.indexOf()が桁違いに速い
  • いまのところArray.prototype.lastIndexOf()は遅い
  • 少し条件が込み入ってくるとforループが最速になることもある

というところでしょうか。v18でもネイティブで実装されたlastIndexOf()よりもforループのの方が早くなるケースがあるというのは若干複雑な気持ちにはなりました。