Closed kachick closed 2 years ago
久しぶりに新しいバージョンリリースする前に計ってみたらめっちゃ遅くなってた。特に基本機能は何も変えてないのでおかしいなぁと思ったら、どうやら Ruby 3.2.1 だと 3.1.3 の半分以下にパフォーマンスが落ちる。 他の gem 達は大差ないっぽいので、なんか 3.2 系で冷遇されてる機能使ってたんやろか・・・?
顕著という程かは難しいけど、有意な差が出たのは SecureRandom.random_number
にでかい上限値指定した時かなー
無指定、小さい数値、random_bytesに関しては殆ど差が出ないのに対して、有意に遅くなってる。とはいえ15%とかそこいらなんだけど・・・
というのがあるのはさておいて、irb上から measure で計ったら遅くなってるどころかむしろ早くなってた なんだろう・・・テスト環境構築の bundler 周り問題なのかなー
benchmark-ips の使い方が悪かったという問題でもあるんだけど、ベンチマーク部分と違う部分で時間を消費していたらしく、該当部分だけに絞ったらちゃんと早かった・・・
(これはこれで何かが遅くなってるんだろうから気にはなるけど)
ref: #18, https://github.com/kachick/ruby-ulid/pull/213, https://github.com/kachick/ruby-ulid/pull/215
元々 golang の https://github.com/oklog/ulid みたいな inspection 機能が、Ruby実装で一番メジャーと思われる https://rubygems.org/gems/ulid に無くてぐぬぬとなったのがきっかけだった。タイムスタンプがIDに含まれるというのが売りのULID使っていてそのタイムスタンプ抜き出せないとか辛すぎる。(今は Shopify の方から機能追加のPRが出ていてレビュー待ち状態) そして https://rubygems.org/gems/ulid-ruby にタイムスタンプ抜き出す機能があるとわかってやれやれとおもいきや、どうも値がおかしい。として調べて行ったら ulid gem も ulid-ruby gem も milliseconds の精度扱いにバグがあって、ソート可能なのが売りなULIDで正しいソートができないという状況に悲鳴を上げた。 この精度の問題にはもうパッチがマージされているので今の最新版なら問題はないはず。
ただこの時仕様を幾つか調べた結果、本家仕様やgolangの方に含まれている
Monotonicity - 同じタイムスタンプでもソート可能にする
機能はどちらのgemにも無い等わかって、久しぶりに自分でも gem を作ってみた感じだった。(そもそもこの仕様自体イマイチではという issue は上がっている)動機が動機なのでリッチにする方向に舵を取っていて、あんまり速度面は気にしないようにしていた。大体 ulid gem の 2/3 ぐらいのID生成速度だったと思うんだけど、最速を目指しているわけではないにせよロジック的にそんな遅くなりそうな気もしないんだけどなーと思ってあれこれやってみた結果、他より速くなってしまった。生成に関しては他のgemの 1.4倍 ~ 1.7倍、パースに関しては 2.6倍ぐらいの速度。
調べた結果
String#gusb(regexp, hash)
をString#tr(string, string)
に置き換えるとその部分の速度自体は2倍ぐらいになった。複雑な処理が必要ない(筈)な場所なので済んだ感。 tr 初めて使ったかも・・・ 大体ULID周りの実装はみんなシフト演算で実現してると思うんだけど、個人的にはシフト演算使うと自分で書いたコードも読めなくなるし、Rubyでもこういうのやるのが本当に速度向上につながるんかいなと思ってたからシフト演算使わないまま済んでホッとしている。追記