Rubyの速度的なネックはどこにあるのか

大変いまさら感だが、RubyKaigi2008での星氏の発表。
Ruby のゲーム開発の現状と自作ゲームライブラリ Star Ruby - 星一
http://www.nicovideo.jp/watch/sm3733775
検索して出てきたのがこれだったからのっけてるけど、ニコニコのんはちょっとコメントがアレなのでオススメできない。
それを踏まえて見るか、コメント消すか、自分で検索してみるなりしたほうがいいかも。


内容について、見たい人は見ていただくとして、ここではその質疑応答の中で「Rubyでゲームを作る場合に、速度的に気をつけなければならないポイント」というのがあったので、俺的なイメージを語ってみる。
あらかじめ言っておくが、これはきちんと検証したものではなく経験則なので、もっとネックになる部分があるかもしれないし、あんまり関係ないかもしれない。
俺も気が向いたら調べるだろうが、誰か他の人がやってみてくれてもよい。


まず、いくつかサンプルなどを作ってみた結果として、特に遅いと感じたのは大きく分けて以下の2点。
(a)メソッド呼び出し
(b)オブジェクトの生成と解放、GC


(a)は、Rubyの動作は基本的にほぼ全てがメソッド呼び出しと言えるから、これが遅いのはRubyが遅いと言っているようなものだ。
インタプリタは最適化してくれないし、1.9のコンパイラがどういう動作をしているかわからないので、とりあえず書いたとおりに動くと解釈する。
全体的に遅い言語であれば、そもそも動作の遅いCPUを使っていた時代の最適化手法を参考にするのがよい。
すなわち、計算を極限まで削る。
書いたとおりに動いているのなら、見た目でメソッド呼び出しが減るようにすると効果がある。
もちろん、重いメソッドとそうじゃないメソッドがあるから、そこまでキワドイところまでくると難しくなってくる。
ループ回数が多いところの内側は要注意だ。
最も実行される部分を徹底的に最適化するのは、いつの時代も同じだろうが、遅い言語であればその効果の出方がまるで違ってくる。
ループの中の足し算を1個減らしたらCPU負荷が数%減るとかも普通にありえるのだ。


Ruby動的言語なので、メソッドの検索にも時間がかかる。
静的型付けならコンパイル時にアドレスやメモリ参照に変換されるから速いが、動的型付けの場合は常にその場でメソッドがあるかどうか、呼び先はどこかを検索する必要がある。
これを解決する手段はないが、Ruby1.9ではインスタンスメソッドキャッシュ(だったっけ)の機構を有効利用するような書き方もあるかもしれない。
逆に悪化させる手はある気がする。
クラスを派生させた場合、スーパークラスのメソッドが呼ばれる条件は、派生先に定義されていないときだ。
定義されていないかどうかは、メソッドをすべて検索する必要があるから、やたらと深い継承構造にして、一番上のクラスのメソッドを呼んだりしたら大変遅い可能性がある。
前から気になっていることではあるから、近いうちに計測してみよう。


(b)はそれと比べると少しわかりにくい。
オブジェクトを生成するのにはある程度の負荷がかかる。
できれば、一度だけ生成して配列にでも入れておいて、使いまわすような感じがいい。
DXRubyExtensionでは、当たり判定オブジェクトは1キャラに1つ生成して使いまわし、毎フレーム生成しないようにしてある。
そのおかげでちょっと使いにくいかもしれないが。
また、オブジェクトの解放はGCに関連している。
RubyではGCが動作するタイミングは、たぶんシステムが保持できるオブジェクト数を超えたときだろうと思う。
定期的なGCもあるかもしれない。
無駄に大量にオブジェクトを生成すると、GCが頻繁に発生して遅くなるし、解放処理の負荷もばかにならない。
また、生成したまま保持するデータが多いとGCの処理そのものが遅くなる。
従って、極力オブジェクトを増やさず、必要なぶんだけ生成して保持するという感じで作るのがよい。
これを意識しようとすると、どのようにコードを記述したらオブジェクトが作られるのか、というのを知らなければならないので、ちょっと難しい。
この件についてはあまり情報はないだろうから。
ちなみに悪い例はDXRubyExtension同梱の当たり判定範囲描画モジュールだ。
毎フレーム、全判定範囲ごとに文字列を大量生成して破棄しているため、GCが異常に重くなっている。
あれはゲームの調整・デバッグ用に作ったものだから遅くても問題はないが、Rubyでリアルタイム処理をしようと思うのなら、気をつけなければならないだろう。


まあ、そういった用途に使う言語ではないから、そのへんの情報はほとんどないだろうと思う。
が、真面目にゲームを作ろうと思ったら意識せざるをえない。
そのぐらいRubyは遅いのだ。
いつか具体例と効果をまとめてWikiにでも書きたいと思う。
いつになるかはわからんけど。