Rubinius 1.1が公開された(RubiniusのウェブサイトかGitHubのリポジトリからダウンロードできる。またはRVMも利用できる)。
Rubinius 1.1のリリースノートにはたくさんの改善とバグ修正が一覧されているが、新しく追加された便利な特徴もある。
Rubiniusは強力で高速なデバッガを持っていたが、1.1では新しいデバッグ機能が追加された(以下はリリースノートからの引用)。
- デバッガAPIとレファレンスのCLIの追加
- メモリデバッグのためのヒープダンプ機能
- 不良な拡張部分を検出するコードの追加と拡張部分の再コンパイル
- VMとRubyがクラッシュした場合のための'rbx report'コマンド
デバッガはコマンドラインスイッチ(-Xdebug
)を利用することで有効になる。このスイッチを使うと実行開始時にデバッガのコマンドラインが利用できる。またデバッガAPIからもデバッガを使える。"require 'debugger';
を記述してデバッガを起動したいところでDebugger.start
をコールすればいい。
チームは今、Rubiniusのドキュメント作成に忙しい。ドキュメントはコマンドrbx docs
を実行することでも利用できる。このコマンドを実行するとブラウザが立ち上がってドキュメントが表示される。
性能についても着目すべき点がいくつかある。
- オブジェクトのインスタンス変数の自動パッキング(メモリ使用の改善)
- JIT内のブロックインラインニングの実現
- リソースの枯渇を防ぐための新しいGILアルゴリズムの実装
新しいGILアルゴリズムはPython 3.2でのGILの作り直しと同じアイディアが使われている。しかし、Rubinius 1.1はまだGILを持っている。
InfoQは1.1のリリース前にRubiniusの作者であるEvan Phoenix氏に、RubiniusのHydraというブランチについて話を聞いた。このブランチはGILのないVMを生み出すことになっている。
InfoQ: RubiniusからGILを取り除く計画について教えてください。
下記が私が採用した戦略です。
1)まずGILそのものを取り除く。これはとても単純です。C++のクラスをいくつかの場所で呼び出せば済みます。
2)Rubiniusはすでにスレッドローカルなデータと共有データの構造の周辺に構築されています。この共有データ構造にミューテックスを追加し、ほとんどのメソッドにロックを追加しました。ロックし過ぎかもしれませんが、今のところ問題ありません。私はこの作業をスコープを使って自動的にロックとロック解除を行うスコープロックのようなC++の技法を使って単純化しました。
3)JITを導入したときに、ガベージコレクタが安全なGCを行うためにシステム内すべてのスレッドを止めるためのコードを書かなければなりませんでした。JITはもとからRubyのコードを並列に実行するからです。このコードはGILで利用したコードをきれいに再利用しました。
4)スレッドに関係する問題を検出し修正するためにRubySpecのスレッドの仕様を利用してきました。この仕様を使ってたくさんのスレッドの振る舞いを動かせるので、この方法はとてもうまくいきました。多くの問題は、スレッドの適切な開始とクリーンアップを保証することで解決しました。処理の同期をとるためにミューテックスとスピンロックを組み合わせて利用しました。
5)今はRubySpecを全面的に利用して、他の問題を探し始めたところです。
InfoQ: RubiniusからGILを取り除く計画について教えてください。GILは完全に取り除かれるのでしょうか。それとも、拡張部分やその他のシステムでGILが残る領域もあり得るのでしょうか。
拡張部分については利用される余地があると思います。というのは、拡張部分は並列に実行するように設計されていないからです。私たちはCの拡張部分がGCオブジェクトにアクセスするためにハンドルシステムを利用しています。こうすることでスレッドセーフが実現できます。しかし、Cの拡張部分はスレッドセーフではない可能性のあるCのライブラリなどを利用しているので、十分に警戒する必要があると思っています。
すべての拡張メソッドの実行にひとつのロックを使う予定です。つまり、各拡張部分のすべてのメソッドがひとつのロックを共有するようにします。こうすることで共有データにアクセスするコードを分離できるでしょうし、性能も多少改善されると思います。
拡張部分ごとにロックを使う方法だと、システムに対してその拡張部分がすでにスレッドセーフであることを伝えられますし、ロックを省略することもできます。これは明らかにCのAPIの拡張になるでしょうが、この件については拡張部分の作者から既に問い合わせを受けています。
Hydraは将来のRubiniusのバージョンに統合される予定だ。そうなればMRIのバージョン1.9.2がGILを使っている唯一のRubyのVMになる。JRubyとIronRubyにGILはない。MacRubyは少し前にGILを取り除いた。
皆、このGILが何をしているのかを理解するのに興味がある。Ruby 1.9.xのGILの実装がどうなっているのか知るにはElise Huard氏のGIL(GVL)についての記事を読むのがいいだろう。
Rubyに(そしてPythonに)スレッドの平行実行がないことによって、開発者はイベントベースのノンブロッキングI/Oによる解決策とOSのプロセスをまたいだ負荷分散に目を向けるようになった。ノンブロッキングの性質を備えたNode.jsの周辺の盛り上がりも関連しているようだ。
しかし、GILのないRubyのVMとRubyのスレッドの並列実行が主流になると何が起こるだろう。このトレンドが逆さまになるのだろうか。