💨

Rubyを研鑽した話

2023/04/20に公開

研鑽Rubyの話

研鑽Ruby出ましたね。

https://twitter.com/kakutani/status/1646347547685060608

レビューに参加させてもらってコメントさせてもらいました。主に実装周りと性能周り。本書についてはいくつか素敵な書評が出ているのであまり書きませんが、なるせさんが書いていた

https://naruse.hateblo.jp/entry/2023/04/17/200004

やりたいことに対していくつもの書き方がある "There is more than one way to do it" なRuby において、『研鑽Rubyプログラミング』はきっとまだ行くべき道を見定められない人の助けとなることでしょう。

という表現はまさに的を射た書評だと思います。Jeremy 流の書き方のご紹介。いろんな書き方を知るのは良い勉強になります。ただ、素直にすべて鵜呑みにするとまずそうな本だと思うので、自分や人の意見を確認しながら、批判的に読むと良いと思います。まぁ、どんな本でもそうかもしれませんが。

Ruby を研鑽した話

で、Rubyの性能に興味のあるパーソンとしては、14章「ライブラリを最適化する」が気になります。いろいろ基本原則とかいいことも書いてあるんだけど、「14.4 何もかもが遅い場合の対処法」にこんなことが書いてありました。

研鑽Ruby P309からスクショ
研鑽Ruby309ページからスクショ

これ、ary[0]ary.firstは、前者が速いから、そう書き換えてもいいよね、って話。マジかよ、そんなこと気にすんのかよ。

ということで確認してみました(各 125M回繰り返した実行時間。コードは https://github.com/ruby/ruby/pull/7486#issuecomment-1462392591)。

                 user     system      total        real
first        2.601405   0.000000   2.601405 (  2.601454)
[0]          1.258742   0.000000   1.258742 (  1.258762)

まじだ、2倍以上遅い。まぁ、125M回繰り返す用途なんてめったにないので(割ってみると、1回約 20nsと10ns)、正直気にするだけ無駄だと思います。メモリキャッシュミス1回で飛ぶくらい。

書いてて気持ちの良い方を使いましょう。もちろん、ary[0]のほうが読みやすい、書きやすいということがあれば、そっちを使うといいと思います。

ただ、それはそれで気持ち悪いので、Ruby 3.3devではArray#firstは速くなるようにしています(ついでに、lastも)。パッチは vm_call_single_noarg_inline_builtin by ko1 · Pull Request #7486 · ruby/ruby

                 user     system      total        real
first        1.447259   0.000854   1.448113 (  1.448137)
[0]          1.227989   0.000042   1.228031 (  1.228081)
last         1.407864   0.000000   1.407864 (  1.407900)
[-1]         1.238353   0.000000   1.238353 (  1.238378)

まだ若干[0]のほうが速いんですが、だいぶ気にしなくてもいいようになったんじゃないでしょうか。というわけで、本書のおかげでRubyが研鑽された話でした。

蛇足:Structの性能改善 Optimize Struct's accessors by ko1 · Pull Request #5131 · ruby/ruby も、実は出版前の英語版を見て、「前からやりたかったんだよなぁ、やらないとなぁ」と重い腰をあげたという経緯があります。研鑽してる。

同P20からスクショ

ちなみに、「Struct 速くしようと思ってたんだけど、文中に遅いって書いてていいの?」ってコミュニケーションをしたりしてました。

性能評価の難しさ

すぐあとで Jeremy 自身、

こうした細かい最適化にあたっては、新しいRubyがリリースされても依然としてその最適化が
有効かどうかを点検してください。

と書いている通り、こういう細かい話はよく変わります。「遅い」って言われるとこんなふうに速くなったりします。Rubyを書いている限り、正直あまり気にしなくていいんじゃないかなぁ。書きやすく読みやすいコードが一番ですよ(私はインタプリタの性能のためなら汚いコードでも書くけど...)。

「こう書くと速いらしい」という folklore がよく流れます。アルゴリズムが違えば速いことももちろん多いでしょう。でも、メソッドの実装が変わって定数倍の速度変更が起こることも(今回みたいに)あります。たとえばエントリ数が十分小さい(数個)であれば、木を使うよりも線形探索の方が速い、みたいなこともあります。プロファイラで見ると支配的な部分も、ツールの問題で全然明後日な結果をだしているかもしれません。

性能評価は難しいです。でも、難しいから楽しいかもしれないですね。

それはともかく、「なんか遅いなぁ」というのを見つけたら、こんな感じで治ることもあるので、ハックしてみるのはいかがでしょう。そういうのに興味ない方は、お気軽にご連絡ください。気が向いたら速くなるかもしれません。

Discussion