Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

最近のRubyコアの動向: 2022年3月版(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

日本語タイトルは内容に即したものにしました。見出しの階層は原文と異なるものもあります。

最近のRubyコアの動向: 2022年3月版(翻訳)

Rubyコア内部の最近の開発状況を把握する時間の余裕があるRuby開発者は多くありません。そこで、Ruby Bug trackerで行われている最近の開発状況をまとめてみることにしました。ここでは機能提案のみをまとめることとし、バグのチケットは対象外としますが、重要なバグチケットが発生した場合は記事の末尾で言及することにします。

今回は、2022年3月に議論された最も重要なissueを紹介します。

🔗 ドキュメント: 複数のハッシュ値の結合方法を改善

#18611(現在オープン)では、ドキュメントの改善がChris Seatonから提案されました。この改善は、開発者が複数の値を結合してハッシュコードを作成するときの正しい方向を示せるようにします。

どんなときにハッシュ値の結合が必要か

Hashのキーでカスタムクラスを使えるようにしたい場合は、カスタムの#hashメソッドを実装する必要があります。このメソッドは、接続された値を正しいバケット(bucket)に入れる必要が生じたときにVMから呼び出されます。

この機能で解決される問題

多くの開発者がカスタムの#hashメソッドを不十分な方法で使っています。これではハッシュテーブルの衝突が無駄に発生してパフォーマンスが低下してしまいます。

承認された適切な方法を使うことで、開発者がこのメソッドを実装するときに正しい方向に導かれるようになります。この方法はほとんどの場合とても簡単です。

class MyCustomClas
        def initialize(attrs)
        @x = attrs[:x]
        @y = attrs[:y]
    end

    def hash
        [@x, @y].hash
    end
end

また、このベストプラクティスをVM内でもっと最適化すればパフォーマンスがさらに向上するという提案も出されています。

CRubyにWASIベースのWebAssemblyサポートがマージ

#18462(現在オープン)が提案されたのは割と前のことですが、最近になって実現されました(実は3月より前のことでしたが、私が以下のMedium記事を偶然見かけたのは最近のことでした)。

参考: An Update on WebAssembly/WASI Support in Ruby | by kateinoigakukun | Mar, 2022 | ITNEXT

特に問題がなければ、Ruby 3.2でWASIプラットフォームもサポートされる予定です。つまりRubyをブラウザの中で実行可能になるということです。さらに重要なのは、WASIイメージをデプロイしてエッジコンピューティングに利用することも、ちょっとしたスクリプトのデプロイに使うことも可能だという点です。WASIイメージにはRuby VMが含まれているので、スクリプトを実行するコンピュータにRubyがなくてもよいのです。既にRuby 3.2.0 Preview 1をダウンロードすればこの機能を試せるようになっています。

参考: Ruby 3.2.0 Preview 1 リリース

メソッドの不意な上書きを防ぐ

Ed Mangimellによる#18618(現在オープン)では、ライブラリを「利用する」開発者が既存のメソッドを上書きする新しいメソッドを作成したときに何らかの形で通知する方法の追加を提案しています。現時点では、このフィードバックはファイルが解析されるときに例外を発生する形にすべきという提案になっています。

主にこのアイデアに賛成する人からそこそこ反響を得ているものの、コアコミッターからのコメントはまだありません。また、Rubyだけでやれるソリューションもありそうなので、この提案がRubyに取り入れられるかどうかは今後を見守りたいと思います。

GCコンパクションの2つのカーソル移動順を入れ替える

訳注

週刊Railsウォッチ20220419もどうぞ。

Ruby 2.7では手動のGC(Garbage Collection)コンパクションが追加されました(#15626)が、#18619でこのアルゴリズムの変更が提案されています(現在はマージおよびクローズ)。

理由は2つあります。1つ目は、GC後に行われる現在のコンパクションでは、オブジェクトをサイズプール(size pool)間で移動するのが非常に困難であること。2つ目は、コンパクションで一部のサイズプールが取りこぼされることです。現在の進捗状況は以下をどうぞ。

サイズプールについて

サイズプールは固定サイズのヒープで、サイズ次第では複数のオブジェクトを内包できます。現在のRubyには多くのサイズプールがあり、どのサイズプールもそれぞれ独自のヒープと「スキャン用カーソル」「コンパクト用カーソル」を持っているので、この問題が発生します。

IO#timeoutIO#timeout=がすべての(ノン)ブロッキング操作に導入

#18630(現在オープン)は主にFiberスケジューラに関連します。プルリク#5653(現在オープン)がマージされれば、すべてのノンブロッキングIOインスタンスがIOインスタンスごとのタイムアウトを備えるようになります。こうすることで、IO操作を呼び出すたびにタイムアウトを新たに作成してエラーハンドリングできるようになります。

Fiberスケジューラについて

Fiberスケジューラによって、自動切り替えのイベントループを書けるようになります。ノンブロッキングIOイベントが発生するとイベントループが別のFiberを実行し、その結果スループットが著しく増大します。Rubyのこの機能を活用したgemとしては、Fiberスケジューラと同じ作者によるasync gemが最も有名です。

socketry/async - GitHub

可変幅アロケーション: 配列

#18634(現在はクローズ)の機能提案と#5660(現在マージ済み)のプルリクが上がっています。この機能強化はユーザーにすぐ影響するものではなく、長期的なRuby VM改善の一環です。最初の改良は、Stringに可変幅アロケーションが実装されたときにマージ済みです。

可変幅アロケーションについて

現在、ほとんどの巨大オブジェクトはメモリ内のさまざまな場所にデータを分割して保存しています。これはCPUキャッシュがうまく効かなくなってパフォーマンスが大幅に悪化するという問題があります。可変幅アロケーションは、データをメモリ上のメタデータの直後に配置することでこの問題を解決します。これがほとんどのオブジェクトで行われるようになれば、パフォーマンスは大きく改善されます。詳しくは作者による以下の動画をどうぞ。

String#subString#sub!の引数をデフォルトで空文字列にする

#18640(現在オープン)ではsubメソッドの変更が提案されています。作者はデフォルトの置き換え文字列を空文字列にしたい意向です。まだ反響は多くありませんが、今後の成り行きを見守りたいと思います。

Ripperの名前付きフィールド

#18642(現在オープン)は、Ruby向けツールを作成している人なら強く興味を惹かれるかもしれません。RipperはRubyスクリプトのパーサーで、コードに対応する配列を多数含んだ配列を返します。以下はきわめてシンプルな例です。

Ripper.sexp("puts 'wuhu')\
=> [:program,\
 [[:command, [:@ident, "puts", [1, 0]], [:args_add_block, [[:string_literal, [:string_content, [:@tstring_content, "wuhu", [1, 6]]]]], false]]]]

しかしこれを扱うには、プログラム側で暗黙の知識が多数要求されます。提案者は、配列内で暗黙の意味が込められたインデックス番号を使う代わりに名前付きノード名を使うRipper::Treeサブクラスを追加するプルリク#5679(現在オープン)を作成しました。

呼び出し可能なものをすべてProcに強制型変換する

ここ最近のRubyエコシステムでは関数型プログラミングに向かう傾向がありました。これはdry-rbエコシステムで多用されています。Rubyで関数型プログラミング的な方法を使いやすくするために、呼び出し可能な任意のオブジェクトをProcに強制型変換する#18644(現在オープン)が提案されています。

メリットのひとつは、Procカリー化可能にできることです。カリー化するということは、すべての引数を一度に1個の関数に渡す必要がなくなるということです。引数が足りない場合でもエラーを発生せずに残りの引数を受け取れる新しいProcが生成され、すべての引数を渡せば結果が返されます。この手法を使えば、コンポジション可能なよいオブジェクトを書きやすくなることが期待できそうです。

prettyprintの強化

#18654(現在オープン)の記述が実に見事なので、ここでは手短にまとめます。prettyprintで使われるデータ構造には、このクラスをコードフォーマッタで使うための新機能があります。対応するプルリクは#3です(現在オープン)。

IO#wait_readableIO#wait_writableをコアにマージ

#18655(現在オープン)もFiberスケジューラに関連します(Rubyコアの開発を追いかけていると、この方面が非常に活発であることが実感できます)。このissueは既に解決済みらしく、#5694(現在オープン)をRubyコアにマージしようという流れのようです。

次点: バグ編

FreeBSD 13のissue

最近RubyのCIがFreeBSD 13で落ちています。このプラットフォームのメンテナーは現在多忙なので、お手すきの方は#18613にてお声をおかけください。

原文お知らせ

  1. 私のブログをぜひメールでご購読ください。こちらのページで登録可能です。
  2. Mediumの使い心地が気に入りましたら、Mediumメンバーシップ登録のうえ、ぜひ私や他のブログライターを応援してください(5ドル/月、または50ドル/年のみ)。こちらのリンクから登録いただくと、費用の一部が私へのサポートに使われます。その他の費用は発生しません。登録いただいた方に深く感謝いたします。

関連記事

WebAssemblyハンズオン: 実際に動かして基礎を学ぶ(翻訳)

Ruby: mallocでマルチスレッドプログラムのメモリが倍増する理由(翻訳)

Rails: Puma/Unicorn/Passengerの効率を最大化する設定(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。