1 ポイント 投稿者 GN⁺ 2023-12-26 | 1件のコメント | WhatsAppで共有
  • YJIT は Ruby 3.2 と比べて性能とメモリ使用量が大幅に改善され、Optcarrot ではインタプリタより 3 倍以上高速化
  • YJIT の Code GC はデフォルトで無効化され、--yjit-exec-mem-size は新しいコードのコンパイルを停止するハードリミットとして動作
  • RubyVM::YJIT.enable が追加され、コマンドライン引数や環境変数を変更せずにランタイムで YJIT を有効化可能
  • デフォルト gem として Prism パーサーが追加され、Prism.parse(source), Prism.parse_comments(source), Prism.parse_success?(source) API を利用可能
  • ruby --parser=prism または RUBYOPT="--parser=prism" で Prism コンパイラを試せるが、このフラグはデバッグ専用
  • パーサージェネレータが Bison から Lrama に置き換えられ、Lrama の内部パーサーは保守性向上のため Racc が生成した LR パーサーに置き換え
  • pure-Ruby JIT コンパイラ RJIT が MJIT を置き換えるが、Unix の x86-64 アーキテクチャのみをサポートし、実験目的に限定
  • M:N thread scheduler が導入され、M 個の Ruby スレッドを N 個のネイティブスレッドが管理するが、C 拡張との互換性を損なう可能性があるため、main Ractor ではデフォルトで無効
  • it を引数なしで呼び出し、通常のパラメータを持たないブロックで使う方式は非推奨となり、Ruby 3.4 では最初のブロックパラメータへの参照になる予定
  • Regexp::new は Ruby 3.2 で非推奨となった 3 引数呼び出しの代わりに、最大 2 引数のみ許可
  • ext/readline は引退し、今後は ext/readline API と互換性のある pure Ruby 実装 reline に依存
  • ext/readline が必要な場合は gem install readline-ext で rubygems.org からインストール可能で、libreadlinelibedit のようなライブラリを別途インストールする必要はなくなる
  • RubyGems と Bundler は、一部の gem を Gemfile または gemspec に追加せず require した場合に警告を表示し、これらの gem は将来の Ruby バージョンで bundled gem になる予定
  • bootsnap gem を使っている場合、この警告は抑制されるため、このバージョンの制約上、アプリケーションを少なくとも一度 DISABLE_BOOTSNAP=1 環境変数付きで実行する方法が推奨
  • デフォルト gem として prism 0.19.0 が追加され、racc 1.7.3 は default gem から bundled gem に昇格

1件のコメント

 
GN⁺ 2023-12-26
Hacker Newsのコメント
  • Ruby 3.3でRubyは大きく復活したと思う。開発者の幸せに注力する一方で遅いと揶揄されていた言語が、今ではもう遅くない。
    YJITは驚くべき技術で、オブジェクトshapeやさまざまなガベージコレクション最適化と合わせて、Rubyはかなり速くなっている。Shopifyのような大規模なRuby利用企業も、3.3のプレリリースでYJITを有効にして運用し、2桁パーセントの性能改善を報告している。
    個人的にRubyとその将来が本当に楽しみで、Ruby 3.3で作業して顧客の本番サイトに適用してみたい。
    https://railsatscale.com/2023-09-18-ruby-3-3-s-yjit-runs-sho...

    • 多少の性能向上でRubyを新たに選ぶようになるかは分からないが、段階的に改善されるのは歓迎だ。性能を過度に心配するのはほとんどの場合早すぎる最適化で、Rubyはこれまで求められた仕事には十分速かった。
      RedisベースのDNSレコードストアとPowerDNSの間のグルーコードにも使ったが、スタック全体が小さなVPS 14台で月5億クエリを処理しつつ、htop上ではほとんど目立たなかった。性能のためにPowerDNSを使ったわけではなく、公開インターネットにさらされる暗号化・HTTP・DNSのようなものを自前で実装するのは普通よくないからだった。
      最近のWebの皮肉は、「遅い」Rubyとサーバーレンダリングで作ったWebアプリのほうが、実際に遅い結果整合性データベースと肥大化したフロントエンドWebアプリよりページ読み込みが速いことだ。現代のWebでは、ちょっとしたことをするだけでもローディングスピナーをあまりにも頻繁に見る。
    • Ruby言語自体は速くなり得るが、エコシステム全体は苦痛なほど遅い。データベース検索や他サービス呼び出しを経て、リクエストごとに1MBのJSONを返すサーバーをRailsで作ると毎秒100リクエスト程度だったが、同じサービスをGoで書き直すと毎秒10万リクエストを処理した。
    • 「2桁の性能改善」が10%速いという意味なのか、10倍速いという意味なのか気になった。
      リンクを開いてみると10%台の改善だった。Rust、Java、Go、C++のような「速い」言語よりRubyがおよそ50〜200倍遅いという認識には、あまり影響を与えられなさそうだ。
    • Rubyが開発者体験を改善できる領域の一つは、より良いデバッグ体験だ。Chrome DevToolsに慣れすぎたせいか、最後にメタプログラミングの多いRubyコードをデバッグしたとき、何が起きているのか把握するのが苦痛だった。
    • 「2桁」と聞いて50%や80%を期待したが、リンクを見ると**13〜15%**だった。
  • Ruby 3.3は過去10年で最も重要かつ機能豊富なRubyリリースの一つに思える。Pythonより先に本番投入可能なJITを出すとは思わなかったし、Prism、Lrama、IRBもある。
    ただ、十分に取り上げられていないのがRactor、M:Nスレッドスケジューラ、Fiber、Asyncだ。特にRailsの文脈で、これらの機能を本番環境で使っている人がいるのか、考えを聞きたい。

    • RubyがPythonより先に本番投入可能なJITを出したのは十分予測できた。Rubyには、ホストインタプリタの実装詳細ごとに依存する巨大な科学計算コミュニティがなかったからだ。
    • Ruby 3.3がそれほど重要なリリースなのか気になる。何がそんなに意味深いのか分からない。
      それでもRactorはもっと注目されていい。ものすごく大きな機能だ。
    • RubyとPythonの両方をまたぐ単一のジョブキューがなぜ存在しないのか本当に理解できない。ある時点から人々がHTTPベースのマイクロサービスで情報をやり取りし始めたのは分かるが、結局のところ、両言語が共有する保存形式を持つ単純なジョブキューのほうが、Ruby/Railsベースのシステムと機械学習スタックをつなぐより良い方法だ。
      おそらく企業内部にはRabbitMQやRedisベースの非公開なカスタム解決策が何千もあるのだろう。
  • 毎年クリスマスになると、時計のようにRuby Langが新リリースを出す。

  • Herokuで利用可能: https://devcenter.heroku.com/changelog-items/2772

  • 良さそうだ。新しいIRBは、補完とデバッグがより良くなった対話型Rubyインタプリタだ。Ruby 3.3の変更の多くは、開発者ツールの改善につながりそうだ。
    言語APIはおおむね以前のリリースとの一貫性を保っている。複数のバージョン管理ツールごとのメモを含めて、Ruby 3.3アップデートガイドを書いた: https://mac.install.guide/ruby/update.html
    気になるのだが、どのバージョン管理ツールを薦めるべきか分からない。以前はasdf、frum、chrubyを薦めていた。

    • rbenvやasdfに特に問題は感じていない。ローカル環境と本番環境の両方で使っている。
  • Socket.getaddrinfoのような名前解決を、今では中断できるようになり、名前解決が必要になるたびにworker pthreadを作ってその中でgetaddrinfo(3)を実行するという。
    他の言語ランタイムも同じようにしているのか気になる。スレッドを作るのは重すぎるように見えるが、実際には大きな問題ではないのかもしれない。独自ベンチマーク基準でもオーバーヘッドは小さいがゼロではない。
    10000.times { Addrinfo.getaddrinfo("www.ruby-lang.org";, 80) }はパッチ前2.3秒、パッチ後3.0秒で、100.times { URI.open("https://www.ruby-lang.org";).read }はパッチ前3.36秒、パッチ後3.40秒だった。

    • 標準ライブラリのすべての入出力操作がasync/fiberをサポートする必要があるからなのか気になる。
      Pythonのように同じ操作をasyncの「色」で再実装したのではなく、すべてが基本的に非同期へ移されたという印象を受けたが、それで合っているのか分からない。
    • 新しいスレッドを作るよりfiberのほうが軽いのではないかと思う。
  • すでに Python と NodeJS を知っているなら、Ruby を学ぶ価値があるのか気になる。Ruby は興味深いが難しく感じる

    • Ruby は基本的に、人気はやや低いがよりエレガントな Python に近い。堅実な汎用言語で、特にシェルスクリプトやデータ整理のような作業に向いている
      Node と Python に習熟しているなら、かなり学びやすいはず。欠点は、それらの言語をすでに知っているなら、根本的に新しいことをもたらしてくれるわけではない点。利点は主に美学的なもので、Ruby はコードを本当に美しく表現する方法を提供し、またそれを促してくれるので、それを体験する楽しさがある
    • Ruby は Python や Node よりも、シェルスクリプト的な作業やシステム作業のための対話的・探索的プログラミングにずっと向いていると思う。「より良い bash」や「より良い Perl」として使うだけでも十分価値がある
      主に TypeScript のコードベースで仕事をしているが、ログデータや半構造化テキストを扱ったり、複数ファイルに対して正規表現ベースの書き換えをしたりするときには、Ruby をよく取り出して使う。Ruby はとても楽しく、定期的に使った言語の中ではおそらく一番楽しい言語なので、それ自体が報酬になる
    • 何を得たいかによる。一番興味深い部分は、Ruby が多くの面で Python と非常によく似ていながら、同時にかなり違っている点
      最大の例は、Ruby がブロックを本当に好むこと。標準ライブラリのあちこちにあり、構文糖も多く、ブロックを中心にした DSL も数えきれないほどある。標準的な関数型機能も標準ライブラリに昔から入っていて、関数型スタイルをなめらかで読みやすく書ける
      Python でも技術的には大半は可能だが、書くのも読むのもずっとぎこちなく見える。Python にはラムダがあるが、ごく些細な用途以上にはあまり好まれていない感じで、その代わり関数がどこでも第一級の値として使われる
    • 学びながらコード改善のヒントを得るには Rubocop を使うとよい。優れたリンターであり教師でもある
    • 10年少し前の 2011〜2013年に、Ruby、より正確には Rails の Ruby を少し使った。当時はすでに 2005年に登場し、2007〜2009年に大きく流行した RoR の余韻が残っていた時期だった
      最新技術に敏感な人たちは、RoR で作ったものよりはるかに速い node.js と AngularJS ベースの API 指向開発へ移っていた。2013年の RoR は標準的なやり方が依然としてモノリシックで、フロントエンド/バックエンド分離という新しいパラダイムにうまく移行できず、古びて見えた
      Ruby 自体ではなく Ruby 製フレームワークの話を長くした理由は、今でも Ruby 開発の 95% は Rails アプリケーションなのではないかと思うから。Ruby が有名になったのは大部分が Ruby on Rails のおかげであり、RoR が下降線なら、Ruby も Perl のように小さい熱心なコミュニティへ縮小していくまで同じ流れをたどる気がする
      言語自体だけを見ると、Python や TypeScript の代わりに Ruby を選ぶ理由が思い浮かばない。言語としてもプラットフォームとしても、すでにより定着している競合より Ruby が優れている点は見当たらない
  • Prism が興味深い。これを使う Ruby コード解析ツールがあるのか気になる。会社のコード解析方法を探していた

    • Ruby LSP が Prism を使っている。Kevin Newton が Rubocop と併用できる whitequark/parser gem 向けの Prism ベースのバックエンドを実装している: https://github.com/kddnewton/parser-prism
  • RUBY_MAX_CPU=n 環境変数が最大 N 個、つまり最大ネイティブスレッド数を設定し、デフォルトは 8 だという
    デフォルトは Rust の Tokio や多くの M:N ランタイムのように、論理コア数であるべきではないかと思う

    • 後から追加できる最適化で、少し微妙な点がある。記憶では Go も数年間は似たような状況で、init()main()GO_MAX_PROCS を設定していた覚えがある
    • 最大 CPU 数にハードキャップをかけるのは正しくないように見える。利用可能なコア数に依存すればよいのではないかと思う
  • Ruby 4.0 では、今のような暗黙的でグローバル名前空間に gem を取り込む方式ではなく、明示的 import を許可してほしい

    • Chris Salzberg の Im に興味を持つかもしれない。Ruby 3.2 でもすでに利用できる: https://github.com/shioyama/im
      検討段階の “namespace on read” 機能に関する議論もある: https://bugs.ruby-lang.org/issues/19744
    • 暗黙的であれ明示的であれ、グローバル名前空間は問題ないと思う。理論上はぎこちないが、実際には慣習と社会的規範のおかげで問題になることはまれ
      グローバル名前空間が各 gem の正確に 1 つのバージョンしかサポートしないという点は、安定した ABI と廃止猶予期間を重視する健全な文化を促しもする。ある言語エコシステムと比べると夢のような環境
    • これは Ruby ではなく Rails 側の話ではないかと思う。ほとんどのプロジェクトではその違いが実質的にないのは分かるが、Rails 開発陣の判断であって、Ruby 開発陣がやっていることとは無関係かもしれない
      あるいは、自分が完全に見当違いなことを言っているのかもしれない
    • Ruby 4.0 は 2030年より前には見られないだろう
      https://youtu.be/4MM5b2F9zrM?si=UT3aUbD6p_uBZehS&t=2347