- blogs:
- cles::blog

Ruby 1.8 と 1.9 のスレッドの違いにハマる


先日ちょっと書いたRuby から MSMQを使う話の続き。
このプログラムをちょっといじって、スレッドを使って複数のキューを待つようにしてみたら、うまく動かなくて色々試行錯誤したのでメモ。
結論から述べると、スレッドでやりたい場合にはRuby 1.9系に移行するのがいいみたいです。
どうしても1.8でやりたい場合には、forkなどを使ってマルチプロセス化しないといけなさそうな感です。
この対処方法は誤りです。現状のWin32OLEはマルチスレッド動作しません。
† サンプルプログラム
今回使ったサンプルプログラムはこんな感じ。
Receive時にタイムアウトを指定して、メッセージがなくても定期的に処理が戻ってくるようにしています。
これをやっておかないとスレッドが永久にブロックしてしまって、スレッドが終了できなくなってしまうので。
qget.rb
† Ruby 1.8 で動かした場合
このプログラムは指定された数のスレッドを起動し終わると「waiting...」が表示されます。本来であればプログラム起動直後に「waiting...」が表示されるはずですが、上記スクリプトをRuby1.8で起動してみると、スレッドがうまく切り替わってくれないので「waiting...」が表示されるまでものすごい時間がかかります。Ruby1.8のスレッドは確か独自実装だったはずで、WIN32OLE経由で呼び出した先の部分はRubyの管理下ではないので、その部分でブロックするようなプログラムを書いてしまうとスレッドがうまく切り替わってくれないようです。
† Ruby 1.9 で動かした場合
これに対して、Ruby 1.9 からスレッドがネイティブスレッド実装になっているのでRubyの管理下にない部分でもスレッドが並列実行されるようです。
一見うまくいってるように見えたので勘違いしてしまいました。おそらく下記のGVLのせいだと思いますが、Ruby 1.9で実行してもRubyの管理下にない部分が勝手に並列に実行されることはないことが分かりました。
嘘を書いてしまってごめんなさい。
スレッド
ネイティブスレッドを用いて実装されていますが、 現在の実装では Ruby VM は Giant VM lock (GVL) を有しており、同時に実行される ネイティブスレッドは常にひとつです。 ただし、IO 関連のブロックする可能性があるシステムコールを行う場合には GVL を解放します。その場合にはスレッドは同時に実行され得ます。 また拡張ライブラリから GVL を操作できるので、複数のスレッドを 同時に実行するような拡張ライブラリは作成可能です。
実際に実行してみるとこんな感じで、すぐにスレッドの起動が終わって各スレッドが並列に実行されています。
Ruby 1.9はいろいろ変わっているので、このためだけに移行するのはちょっと気が引けるんですが、どうしようかなぁ。。。。
このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/3846
古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
コメントは承認後の表示となります。
OpenIDでログインすると、即時に公開されます。
OpenID を使ってログインすることができます。
2 . 福岡銀がデマの投稿者への刑事告訴を検討中(112443)
3 . 年次の人間ドックへ(111913)
4 . 2023 年分の確定申告完了!(1つめ)(111487)
5 . 三菱鉛筆がラミーを買収(111366)