Ruby 2.7のここがすごい! パターンマッチ、コンパクションGCなどをリリースマネージャーに聞いた
2019年12月25日にリリースされたばかりのRuby 2.7では、どのような機能がどういった経緯で採用されているのでしょう。リリースマネージャーのnaruseさんと、フルタイムコミッターのmameさんに詳しくうかがいました。
- まつもとさんはとにかく忙しくて
- 実はすごいirbの改良
- パターンマッチはRubyをどう変えるか
- キーワード引数は、端的に壊れていたのを大整理した
- 高速化に向けたいくつかの観点
- Ruby 2.7で導入される「コンパクションGC」とは
- Ruby 3のビジョンは「静的解析」「並行並列」「JIT」
プログラミング言語Rubyには、クリスマス前後に新しいバージョンをリリースする伝統があり、2013年の2.1.0以降は毎年12月25日にメジャーバージョンアップが行われています。2019年も無事にバージョン2.7.0がリリースされましたが、Ruby 2.7にはどのような新しい機能が導入されているのでしょう?
Rubyの開発者コミュニティでは、オリジナル開発者であるまつもとゆきひろ(Matz)さんを交えた開発者会議が月次で開催されており、2019年のクリスマスリリースでどの機能を取り入れるかは、11月28日の開発者会議で決定されました。
Misc #16262: DevelopersMeeting20191128Japan - Ruby master - Ruby Issue Tracking System
この開発者会議の直後、リリースマネージャーである成瀬ゆい(naruse)さんと、フルタイムコミッターである遠藤侑介(mame)さんに集まっていただき、Ruby 2.7の新機能について、ラムダノートの鹿野桂一郎(golden_lucky)さんが深く詳しく聞きました。
- 成瀬 ゆい(なるせ・ゆい) nalsh nurse(写真左)
- 2004年からnkfライブラリのメンテナとしてRubyの開発に参加。バージョン1.9から文字コード全般に関わるようになり、バージョン2.1から現在までリリースマネージャーを務める。トレジャーデータ株式会社所属。
- 遠藤 侑介(えんどう・ゆうすけ) mametter mame(写真右)
- 2008年からRubyの開発に参加。テスト支援機能などのRubyの高品質化を中心に活動し、Ruby 2.0ではリリースマネージャーも努める。2017年からクックパッド株式会社で、笹田耕一氏に続く同社2人目のフルタイムコミッターとしてRubyの開発に専念する。著書に『RubyでつくるRuby ゼロから学びなおすプログラミング言語入門』(ラムダノート、2017年)など。
まつもとさんはとにかく忙しくて
──今日はRuby開発者会議の後にお時間をいただき、ありがとうございます。開発者会議には、まつもとゆきひろさんも参加されていたのですか?
naruse はい。そもそもRuby開発者会議は、3~4年くらい前に「まつもとさんに直接意見を言って、判断してもらう場」として始めたので、リモートでもいいから基本的にまつもとさんには参加してもらっています。
全ての機能提案に対してYes/Noを答えてもらうのが理想なんですが、まつもとさんは本当に忙しくて。一時期は、新しい機能を判断してもらう機会が「カンファレンスなどで捕まえて直談判」しかないという状況があり、それで月に一回、定期的にこういう会議を開くようになりました。
mame 会議が近づくと開発者会議チケットを切るので、議論してほしいバグ報告や提案があればチケット番号と要約を書いてもらい、会議のアジェンダとしています。
naruse 運用には試行錯誤もあったんですが、最終的にチケットを利用した現在の方針にたどり着きました。
──今日の開発者会議で俎上に載ったチケットはいくつあったんですか?
naruse 20くらいですね。
──開発者の方はたくさん参加されるのですか?
naruse 今日は10人くらいでした。平日なので参加できるメンバーは限られますが、クックパッドでフルタイムのコミッターになった遠藤さんをはじめ、最近は平日の開発者会議に参加できるメンバーが増えてきたので、やりやすくなりました。
──現在のRubyで、まつもとさんはどういう形でリリースにかかわっているんでしょう。
naruse まつもとさんが、現在のRubyでリリース版のコードに対して何らかの作業をすることは、滅多にありません。昨年の2.6でKernel#thenを自ら追加していますが、これはかなり久しぶりですね。
ただし、各バージョンごとに1つだけ、欠かさず実施してもらっている作業があります。それはversion.h
の内容、つまりバージョン番号を更新することです。これだけは、儀式的な意味も込めて、まつもとさんに毎回お願いしています。
──新機能の追加といった判断は、リリースマネージャーである成瀬さんがされているのでしょうか?
naruse いえ、新機能の追加は、コミッターが直接リポジトリにpushしています。
ただし、Rubyでプログラムを書くユーザーが直接目にするような側面については、まつもとさんのOKがないとpushできません。Rubyの仕様に変更が出るような改良、例えばメソッドが追加されるといった場合は、まつもとさんの判断が必要です。
将来は、Pull Requestしてもらって誰かが承認するという手順になるかもしれませんが、いまのところは各自が自由に開発に参加して、うまく回っている感じです。
実はすごいirbの改良
──それではいよいよRuby 2.7の新機能についてですが、まずはユーザーに身近なところで、REPLの改良についてお聞きしたいと思います。
naruse このirbの改良は、Ruby Prize 2019の受賞作なんですよ。
──Ruby Prize?
naruse Rubyコミュニティの新人賞で、新しく活動に参加して顕著な実績があった個人を、松江市で毎年開催されているRubyWorld Conferenceで表彰しています。
2019年の受賞者は糸柳茶蔵(aycabta)さんで、その主な授賞理由が、今回のRuby 2.7に入ったirbの改良でした。
──プレビュー版のリリースノートに、実際に動作している様子が埋め込まれてますね。この手のドキュメントに動画は珍しいのでは?
naruse 新しいirbを使っている場面を実際に見てもらえば、一発で伝わるだろうということで、動画にしました1。Rubyの構文が解釈されて色が付いていますし、複数行にわたる編集が可能であることも伝わるでしょうから。
──確かに「複数行編集ができるようになりました」と文章で言われても、あまりピンとこないですね。
naruse いや、実はすごいことなんですよ。Webブラウザのような高級なアプリでも、あるいはものすごく最近に登場したプラットフォーム依存の言語でもなく、どのOSのコンソールでも複数行にわたる編集ができるREPLがあるプログラミング言語は、なかなかないと思います。ひょっとしたらJavaはできたかもしれませんが。
──そもそもJavaにREPLがあったんですか?
naruse 実はJava 9から入っているんです。
個人的に、最近は「ターミナルルネッサンス」とでも呼べるような活況だと感じていて、端末アプリにかつてない脚光が当たっています。特に気合いが入っているのはMicrosoftで、Windowsの端末環境は急速に良くなっていますよね。
──その潮流を受けて、irbも進化したということなんでしょうか?
naruse 実際には、いわゆるReadlineライブラリを使って、今回のようなirbの改良を実現するのは無理だったと思います。
糸柳さんがすごかったのは、ReadlineをRubyだけで再実装し、それによってirbの改良をクロスプラットフォームで実現させたことです。そのReadlineの再実装が、リリースノートにもあるrelineというライブラリです。
GitHub - ruby/reline: The compatible library with the API of Ruby's stdlib 'readline'
mame 実際にはReadlineを包含しているので、relineは「Readlineよりすごい」よね。
naruse Readlineの再実装は、世界中の凄腕の開発者たちが挑戦している課題なんです。
例えば、macOSのデフォルトの環境ではReadlineが使えなくて、editlineというBSDライセンスの互換実装が動いています。しかし、このeditlineは多言語対応が弱くて、「MySQLのREPLで日本語が通らない」といった経験をしたことがある人も多いと思います。
また、Readlineの機能を実現するライブラリにはプラットフォーム依存の問題もあって、もちろんeditlineはWindowsでは動かないですし、Readlineそのものも最近のバージョンはビルドできなかったりします。
そんな具合に、Readlineまわりには多言語対応とクロスプラットフォームの問題があるんですが、これをクリアするためにRubyで実装しました、ってのがrelineです。
過去にもReadlineをRubyで再実装する試みがなかったわけではないのですが、irbを置き換えるレベルで実装し切ったたことが、relineの偉大さです。
mame 糸柳さんがReadlineをRubyで再実装している話はずいぶん前から聞いていたんですが、難しいだろうなと思ってたんですよ。ところが今年の半ばくらいに完成したものを見て、「ここまで動くの?!」と驚愕しました。これがWindowsを含めた各種OSで動くのか、と。
──これはirbだけでなく、Pryにも導入されるんですか?
naruse まだみたいですが、将来的にrelineに乗り換えたいという話は聞きました。JRubyでも動きます。
──REPLの改良の話は意外と大きかったんですね。
naruse わたしがRubyのリリースに関することをツイートして、リプライなどの反応があるのは、だいたいREPLの話ですね。
ただ、色が付いたことのインパクトが大きくて、複数行編集のすごさには、まだあまり気づいてもらえていないかもしれないと心配しています。実際に触ってもらえると、本当にすごいんですよ。将来は、補完機能やヘルプ表示も、よりいっそう強化できればと思っています。
mame 成瀬さんは、これが「ターミナルの将来を変えていく」「新世代のターミナル環境のきっかけになる」とまで考えてますよね。
naruse そうですね。Ruby 2.7で導入されるirbの改良からは、ターミナル環境のさまざまな可能性を感じています。
パターンマッチはRubyをどう変えるか
──Rubyのユーザーから見て大きな機能追加に、パターンマッチがありますね。
naruse パターンマッチについては、かなり前から「欲しい」という声がありました。最近では関数型言語の利用も増えてきたため、その声がいっそう大きくなっています。なるべくRubyの文法に似たパターンマッチのライブラリを考えた、といった発表も、何年も前のRubyKaigiからありました。
それこそ「Rubyでプログラムを書くユーザーに直接触れるところ」なので、どんなキーワードを使うかといった点も含めて、まつもとさんの判断が必要でした。いろいろな提案もあって、ずっと議論はしていたんです。
──なぜ今回のリリースで入ることになったのでしょう?
naruse なぜ今年のリリースか? と聞かれて答えるのは難しいんですが、パターンマッチ担当の辻本(和樹、k-tsj)さんが「思い切って実装したから」ですね。結局「個人の情熱」みたいな部分が、機能追加の実現には大きな要因になるので。
紙の上で仕様を議論していてもなかなか進まないんですが、誰かの気持ちが盛り上がってマージできるような実装を作り上げて提案されると、急に話が進むことがあります。辻本さんのやる気が去年出ていたら、去年のリリースに含まれていたかもしれません。
あとは背景として、近年のWebアプリケーションの複雑化が、パターンマッチの積極的な導入を後押しした面はあると思います。REST APIとか、Webアプリケーションのルーティングを書くために、パターンマッチが使えるかもしれないという話は聞きますね。
──Rubyでパターンマッチが便利に使えそうなのは、どんな場面ですか?
mame 有望な用途としては、JSONの分解などがあるかもしれません。JavaScriptには分割代入(Destructuring assignment)という仕組みがあって、JSONを分解しつつ中身をうまく取り出す処理を、うまく書けます。それと同じことをRubyでもやりたい、と思っている人はいるはず。
naruse そうですね。ArrayやHashのdigメソッドのような操作を一気に複数やりたい、といった要望ですかね。JSONのデータからSQLのクエリを効率よく作りたい、という話を聞いたこともあります。
とはいえ、何かの要望に対して「パターンマッチが使えそう」ということと、「パターンマッチがあれば書ける」ことは別の話じゃないですか。パターンマッチに限らず、ブロックチェーンなどもそうですが、うまく使えそうな場面があるとして、それが本当にできるかというと何とも言えない面がある。
mame パターンマッチが欲しいという声はずっとあったので、かなり議論をして入れることにはなったけれど、実際どう使えばいいのかは、正直なところよくイメージできていないところはありますね。言語の機能がどう使われるかは、想定できない面もあるので。
naruse パターンマッチは、関数型と呼ばれる他のプログラミング言語のパラダイムの、いわば輸入にあたります。なぜ他の言語のパラダイムをわざわざRubyに導入するかというと、それによって書きやすくなるプログラムや、書けるようになるプログラムがあるからなんですが、それは使う人に考えてもらえればよくて、開発者サイドとしては、まずパラダイムを導入することに意義があると考えています。
mame 別のパラダイムからの輸入という観点でいえば、今までのRubyのパラダイムでは「いかにもパターンマッチがはまるようなプログラム」は書かれてこなかったので、既存のRubyプログラムの中に「パターンマッチで置き換えたい」と思えるものがあまり見当たらないのは当然だとも言えます。
逆に、これからRubyで関数型プログラミングっぽい書き方をしたい状況が出てきたときに、今回のパターンマッチの導入でやりやすくなることは、期待できるかもしれません。
──他の言語のパラダイムを取り込むというのは、そういうことですものね。
mame 当たり前と言えば当たり前の話なんですが、そう思います。
むしろ開発者側からすると、「今までRubyになかったパラダイム」をどうRubyに取り込むかという面が大変でした。
Ruby 2.7のパターンマッチの設計については、辻本さんがすごく丁寧にまとめた記事が『n月刊ラムダノート』にあるので、ぜひ読んでもらいたいです。
n月刊ラムダノート Vol.1, No.3(2019)(紙書籍+PDF版) - 技術書出版と販売のラムダノート
naruse プログラミング言語のある機能をどう設計したか、という話がここまで詳細に紙の媒体に残されることってあまりないですしね。
mame 辻本さんは途中の議論をすごくよく覚えていて、それがすごい。いろいろ考えて作っても、どう考えてそういう設計にしたのかは、どうしても忘れがちなので……。
──パターンマッチについては、まつもとさんによる判断もかなりあったそうですね。
naruse そうです。コードができる前からまつもとさんを交えてかなり議論していました。パターンマッチの関係者は去年から集まってミーティングしています。キーワードとしてin
を使うといった判断も、そうした経緯で決まったものです。
キーワード引数は、端的に壊れていたのを大整理した
──今回のリリースで遠藤さんがかなり頑張っているように見えるのは、キーワード引数の改良ですが、これまでどのような問題があったのでしょうか。
mame Ruby 2.0で入ったキーワード引数の扱いは、端的に言うと、壊れてたんです。最初はおおむね問題なく動く状態で導入したんですが、「直観に反する」という意見に対してアドホックに動作を変えていったら、ついにどうしようもなくなってしまった。
それを大整理したのが今回のポイントです。ジェレミー(エバンス、jeremyevans)さんと一緒に頑張りました。
具体的には、普通の引数とキーワード引数を一緒に渡せるようにしていた設計に無理があったので、それをあきらめて両者をきっちり分けることにしました。
それに伴って非互換が発生するので、うまく移行できるように考えました。
──再び直観に合わなくなることはなかったんですか?
naruse 今までのキーワード引数は、2種類の情報をいったん混ぜてしまうことで情報が落ちていた点が、直観に反する挙動の根源的な原因です。今回は、少なくともその点に起因する問題はなくなっています。
mame 2種類の引数が混ざった状態を受け取る側では、それをまた2種類に分けないといけないんですが、その部分でアドホックな拡張が繰り返された結果、ついに打つ手がなくなってしまいました。今までがモグラたたき状態だったんですよね。
naruse 渡していたものがなくなる可能性があるので、デリゲート(委譲)では特に困ります。
mame Ruby 2.7におけるキーワード引数の整理については、非互換も発生するので、ruby-lang.orgに詳細な記事を公開する予定です。
高速化に向けたいくつかの観点
──他にもユーザーから見えやすい改良点はありそうですが、次はRubyの処理系の改良点についても話をうかがえればと思います。
mame 令和対応の話とかしなくていいですか?
──何か必要な対応があったんですか?
naruse Unicodeに「令和」の合字が追加されたのでその対応と、date
の動作に修正が必要でした。
Unicode Version 12.1 released in support of the Reiwa Era - The Unicode Blog
──なるほど、そういう細かい修正の積み重ねもメジャーリリースでは必要というわけですね。しかし、そろそろもうちょっと低レイヤの話が聞ければと思います。
naruse Ruby 2.7では、高速化に関する改良点として以下のようなものが挙げられます。
- Ruby評価器そのものの高速化
- 特定のメソッドの最適化
- モニターとモニターmixinの改良
Railsやfluentdで使われているモニターは、いままでRubyで実装していたものをCで再実装したので、速くなりました。
──現在のRubyの開発では、大きな流れとして、なるべくRubyネイティブな実装に変えているという話を聞いていました。Rubyで実装されていたものをCで書き直したのは、一見すると逆行しているようですが。
mame 高速化と一口に言っても、Rubyの評価器そのものの高速化もあれば、C APIの高速化のような話もあります。両方とも笹田(耕一、koichisasada)さんが頑張るのは無理なので、笹田さんには評価器の高速化に専念してもらい、C APIについては機能を制限することで高速化を図ろうという話があります。
例えば、C APIではキーワード引数を直接は受け取れないようにして、RubyからCの関数を呼ぶときには固定長の引数だけを渡すように制限し、C APIの部分がネックにならないようにする、といった方針があります。
それはそれとして、モニターは遅かったので、Cで書いた方が速かったということですね。
naruse モニターは、複数スレッド間でアトミックにやらないといけない操作がいくつかあり、ロックが必要になる仕組みなんです。Rubyで単純に書いてもアトミックにはならないんですが、Cで書けば自然にRubyレベルでアトミックになります。Rubyレベルだと根本的に高速化が難しい部分ではありました。
パフォーマンスの改善点については、まだいくつか正式版のリリースノートに書けることがあるはずなので、楽しみにしてください。特にFiberの改善は着実に進んでいます。
正式版のリリースノートでは「パフォーマンスの改善」の項目として、Fiberのキャッシュ戦略の変更(#2224)、メソッド呼び出しごとのキャッシュの改良(#2583)、コンパイル済みバイナリのサイズが削減(Feature #16163)などが挙げられています。笹田耕一さんと遠藤さんによる解説も参照してください。
Ruby 2.7で導入される「コンパクションGC」とは
──高速化と言えば、プレビュー版のリリースノートでも「コンパクションGC」の導入が特に目玉になっていますね。GC(Garbage Collection)の改良は、大規模なWebアプリケーションでレスポンスの高速化に寄与しそうです。
naruse GCの改良は、Webアプリケーションのレスポンス改善というRubyとしては大きな利用シーンに直結する話なので、今回のRuby 2.7では目玉にしました。リリースノートは、そのままニュースサイトで使われることも多いので、開発者側から積極的にアピールしたい順にトピックを並べるようにしています2。
──「コンパクションGC」というキーワードだけで、効果がピンとくる人は限られそうなので、詳しく聞かせてください。まず、なぜこのタイミングなのでしょう?
naruse 今回のリリースにコンパクションGCが入ったのは、端的に言うと「実装できてリリースに入れられる状態になったから」なんですが、その経緯を説明するにはRubyインタプリタにおけるGCの歴史から説明する必要がありますね……。これは、(GCの改良を)実際にやっている笹田さんの近くにいる遠藤さんからぜひ。
──そもそもGCとは何か? からお願いします。
mame ユーザーが書いたプログラムをRubyのインタプリタが実行するときに、配列などのオブジェクトはヒープ領域に置かれます。これはいつか解放してあげないと、利用できるメモリがなくなって、プログラムが動かせなくなります。C言語などでは、プログラマが自分でメモリを解放するようにコードを書くんですが、それを自動的にやってくれるのがGCです。
いろいろな方式がありますが、Rubyがバージョン2.0まで採用していた単純なマーク&スイープ方式のGCでは、まず実行中のプログラムから参照されるオブジェクトを全て見つけ出してマークしていきます。ヒープ領域にあってマークが付いていないオブジェクトは、実行中のプログラムから参照で到達できないので、安心して消去できます。こうしてヒープに空き領域を作り出します。
マーク&スイープ方式では、マークするときに実行中のプログラムをいったん完全に止めないといけないので、これがプログラムの停止時間として、アプリケーションの動作に影響します。Webアプリケーションだと、クライアントからのリクエスト処理が止まってしまうので、利用者からはレスポンスが悪くなったように見えてしまいます。
とにかくリクエストを受けたら早く返したい、というのは、Webアプリケーションでは当然の要望です。
──Ruby 2.0のころには、すでにかなり大きなWebサイトでもRailsが使われていたと思いますが、単純なマーク&スイープ方式で大丈夫だったんですか?
mame 大丈夫な感じではなかったと思います。そのため、クックパッドをはじめRailsをビジネスで使っていた大手サイトでは、アプリケーション側でGCが走るタイミングを抑制するハックを利用してました。OoBGC(Out of Band Garbage Collector)といって、ものすごく簡単にいうと、リクエストを処理している間はGCを動かさない、という方法です。
この方法を採用するとアプリケーションは管理しにくくなるし、潤沢なメモリが必要で、CPUにも負荷が高いので、現在のクックパッドではOoBGCは採用していません。GitHubでも、2018年5月までにOoBGCを完全にやめたらしいです。
Performance Impact of Removing OOBGC - The GitHub Blog
──RubyのGCが改良されたので、OoBGCをやめられたわけですね。
mame 実は、2013年にリリースされたRuby 2.1で、すでに「世代別GC」という改良されたGCが入っているんですよ。
世代別GCは、マーク&スイープの停止時間を短くする工夫のひとつです。GCのたびにヒープ領域全体を調べるとどうしてもプログラムの停止時間が長くなるので、比較的新しく作られたオブジェクトはすぐに不要になることが多いという性質を利用し、ヒープ全体を「新しいオブジェクト用の領域」と「GCを生き残った古いオブジェクト用の領域」に分け、普段は「新しいオブジェクト用の領域」だけをGCにかけるようにします。これにより、マーク&スイープによる停止時間を短くしようというわけです。
世代別GCは、特に新しい手法ではなく、Javaなどでははるか昔から採用されているんですが、これをRubyに導入するのはけっこうな難問でした。
──単にヒープを分割して片方だけをマーク&スイープするのではダメなんですか?
mame Rubyでは、C言語で書かれた拡張ライブラリがたくさん利用されています。GCを改良するとしたら、古き良きマーク&スイープにしか対応していないライブラリでも問題なく動くような形で導入しないといけません。
しかし、マーク&スイープを世代別GCに変えるには、「古いオブジェクトから新しいオフジェクトへの参照が発生していないか」を常に把握しておく必要があります。そうしないと、新しいオブジェクト用の領域をマーク&スイープする際に、それらが「利用されていないオブジェクト」とみなされて解放されてしまうからです。
通常はそのため、全てのオブジェクトにライトバリアという処理を施す必要があります。しかしRubyでは、C言語で書かれた拡張ライブラリがあるためにオブジェクトにライトバリアをかけられない場合が生じ、それが原因で、世代別GCを導入できずにいました。
この問題に対して、笹田さんが解決策を考えて実装し、そのおかげでRuby 2.1で世代別GCが導入できたという経緯があります。ちなみにこの手法は、2019年6月に、メモリ管理に関する国際会議のISMM(International Symposium on Memory Management)でも、笹田さんが発表しています。
ISMM 2019 - Gradual Write-barrier Insertion into a Ruby interpreter
──つまり、C言語で書かれた拡張ライブラリの存在が、RubyにおけるGC改良のネックだったわけですね。
mame RubyインタプリタのC APIを使って拡張ライブラリを書くとき、単純なマーク&スイープなら、オブジェクトのメモリを直接参照しても問題になりません。これは、それを気にせずにC言語で拡張ライブラリを書けるように、RubyのGCをなるべく保守的な設計にしていたからです。
結果的に、サードパーティーの拡張ライブラリがRubyのメモリをどう使っているか分からないので、単純に世代別GCのような仕組みを導入しようとすればセグフォ(segmentation fault)が起きたりします。
笹田さんが考えたのは、ライトバリアをかけるオブジェクトの種類を徐々に増やしていくための方法です。一度に全てのオブジェクトをライトバリアで保護しようとすると、コーディングやデバッグの労力と時間が膨大になります。
しかし、ライトバリアに未対応のオブジェクトが残っていても世代別GCが導入できることが分かったので、利用頻度が高いArrayやHashのようなオブジェクトから徐々にライトバリアにしていくことで世代別GCの恩恵が受けられるようになりました。
この手法のおかげで、現在のRubyでは、世代別GCだけでなく、マーク&スイープを一度にやらずに小まめにやって一回の停止時間を短くするインクリメンタルGCも導入されています。こうしてRubyのGCがどんどん現代的になっている一環として、コンパクションGCの導入もあるという感じです。
コンパクションというのは、ヒープ領域に飛び飛びに残ってしまったオブジェクトをまとめて連続したメモリ領域を増やす手法です。これをRubyに導入したものが、今回の目玉である「コンパクションGC」です。GitHubのアーロン(パターソン、tenderlove)さんが実装してくれました。
──今回のGC改良によるアプリケーションのパフォーマンス改善は、プレビュー版でも確認できているのでしょうか?
naruse パフォーマンスが如実に改善するような規模のサービスだと、GCの改良のようなクリティカルな変更をプレビュー版で導入するのは難しいので、実際にはこれからです。リリースまで1カ月かけて細かい調整やバグの洗い出しをするので、正式リリースでは安心して使ってもらえるようになっていると思います。
Ruby 3のビジョンは「静的解析」「並行並列」「JIT」
──ここまでRuby 2.7の話をうかがってきましたが、次の2.8に向けた動きはすでに始まっているんですか?
naruse 次のバージョンはRuby 3ですけどね。
mame 先日のRubyConf 2019 Nashville(2019年11月18日から20日に開催)で、正式に発表されました。
──2020年にRuby 3が形になるというのは本当だったんですね。
naruse はい。Ruby 3では、静的解析、つまり型と、並列並行処理の強化、それにRuby2.6から実験的に導入されているJITによるパフォーマンスの改善という、3つの大きな柱を考えています。
──静的解析、並列並行処理、JITというキーワードだけを聞くと、いずれもRubyだけでなく現代的なプログラミング言語の多くで強調されている要素ですね。
mame 実装に先立ってキーワードを出している点が、他のオープンソースのプロジェクトとは違うところかも。
naruse キーワードだけ出しているわけでなく、ビジョンとして掲げているんですよ!
──JITは実験的には導入されているし、並行並列に関してはRubyにはすでにFiberという軽量スレッドがありますよね。となると、まだ実装されていないのは静的解析だけでは?
mame 静的解析は、ぼくが頑張らないといけませんね。
──JITはもう実用的に使える段階なんでしょうか?
naruse Ruby 2.6で実験的に導入されていますが、誰でも使える状態にもっていくにはまだ少しかかりそうです。
mame RailsアプリケーションがJITでは速くならないんだよなあ。いまは別の部分に開発リソースが割かれている感じです。
naruse 並列並行については、Fiberを自動化するAutoFiberが検討されてます。AutoFiberは、うまく実装できればRailsアプリケーションが多重化できるようになります。
mame AutoFiberは、IOが待ち状態になったら他のFiberが自動的に動き出す仕組みです。そもそもFiberはOSスレッドとは別で、ある程度アプリケーションによって制御できる実行単位がたくさん作れます。
naruse 要するにコルーチンのかっこいい名前ですよね。用途としてはJavaのNettyとかに似ていて、Fiberを使った軽量なミドルウェアサーバのFalconを開発しているのが、いまAutoFiberをやっているサミュエル(ウィリアムズ、ioquatix)さんです。
GitHub - socketry/falcon: A high-performance web server for Ruby, supporting HTTP/1, HTTP/2 and TLS.
一方、CPUがボトルネックになるようなアプリケーションについては、物理的に複数のCPUを使う並列のための仕組みとしてGuildを開発しています。
Guild Prototype - RubyKaigi 2018(PDF)
mame AutoFiberとGuildの2つが、Ruby 3における並行並列のそれぞれ中核になります。
──静的解析については、少し前から噂は耳にしていますが、もうかなり出来上がっているのでしょうか?
mame まだ難題は多いです。実は、今回のRuby 2.7でキーワード引数に大ナタを振るったのも、型付けをするにあたってまず現状の混乱を整理したかったからなんですが、その整理にかなり時間を使ってしまいました。
──なるほど、今はまずRuby 2.7の正式なリリースに向けて全力を出しているところ、というわけですね。今日はいろいろなお話をありがとうございました。
取材・執筆:鹿野桂一郎(技術書出版ラムダノート)