Railsのスレッドセーフ
Rails2.2からスレッド対応になったと聞いていたけど、スレッドセーフなのか気になって調べてみた。単に、コントローラインスタンスがリクエスト毎に作成されることを確かめただけ。
scaffoldで作成したコントローラに対して下記を書く。
p self.object_id
いくつかリクエストを投げると、以下の主力が得られた。
3602 3654 3706 3758
よしよし。リクエスト毎にコントローラオブジェクトが異なっている。
もう少し詳しく見てみよう。クラス変数として配列オブジェクトを作成し、リクエスト毎に作成されるインスタンスを格納していこう。このようにすれば、リクエストの度に配列サイズが増えていくはず。
下記のように、毎回、配列サイズを出力する。
@@a = [] def index p self.object_id @@a.push self p @@a.size end
何回かリクエストを投げると、
4494 1 4546 1 4598 1 4650 1 4702 1 4754 1
あれれ・・・。予想に反する。配列の要素数がなぜ増えない?? クラス変数なのにインスタンス間で共有されていない・・・。というか、リクエスト毎にクラス自体が別物になっちゃってる??? うー、理解できない。
検索したところ、微熱 everydayを発見。次のように書いてあった。
production ではクラスの再ロードは基本されない。のでコントローラ等で内部DSL るため
そういうことか。developmentでは、リクエスト毎にクラスをロードしてるってことだね。そういえば、どこかで読んだ記憶がある。
RAILS_ENV=productionとして実行すると、期待した結果となった。
2752 1 2756 2 2760 3 2764 4
よしよし。しかしなぜ挙動を変えているんだ?
もしかして、そういうこと?? 知らなかった。Rubyって、ソースを変更したらすぐ反映されるものだと思ってた。それがスクリプト言語の特徴なのだと思っていた。だけど、productionモードだと、上記の出力をコメントアウトにしても、即時に反映されない。つまり、最初にロードされたままになっている。これがRubyのデフォルトの挙動なのかな。これでは開発しにくい。開発時は、APサーバ起動後、頻繁にコードを変更するからリクエスト毎にクラスロードが走らないと困る。
あー知らなんだ。勉強になった。