丁稚な日々

Rubyで遊んだ日々の記録。あくまで著者視点の私的な記録なので、正確さを求めないように。
Rubyと関係ない話題にはその旨注記しているはず。なので、一見関係無いように見える話題もどこかで関係あるのかもしれません。または、注記の書き忘れかもしれません...

[直前] [最新] [直後] [Top]

May.16,2013 (Thu)

Revision: 1.4 (May.16,2013 13:35)

不定期連載「『なるほどUnixプロセス』で学ぶWindows版Rubyの基礎」〜第19章 端末プロセスって何かと思った

_ 要するに外部プロセス起動のことですね。

_ fork+execはforkなので論外だが、Kernel#execについては覚えておいてもいいかな。
Unixにおいては、exec(2)は自プロセスを新たに起動する別プロセスで置き換える、という処理だという理解で概ね問題ないと思う。
置き換える、とはどういうことかというと、pidとかは変えずに、実行されるプログラムが変化する、ということになる。
Windowsにはexec(2)のこういう挙動に相当する機能はなく、MSVCRTのexec系関数がプロセス置き換えをエミュレーションしてくれるけど、これは新しいプロセスのpidが変わってしまうので、pidを使ってProcess.waitpidとかしようとしているコードにとってはあまりうまくない。
というわけで、Windows版Rubyでは、普通に子プロセスを起動した上で、その子プロセスの終了を待ち続けることにより、親プロセスから見るとpidが変わってないふり、を一応している。
せいぜい終了コードを伝えるくらいで、シグナル投げの仲介とかまではしないけどね。
Kernel#execwin32/win32.crb_w32_spawn()関数を第一引数としてP_OVERLAYを指定して呼び出していて、最終的にはchild_result()関数の中でその子プロセス終了を待ち続ける、という処理を行っている。

_ Kernel#systemKernel#`はWindows版Rubyでも何事もなく使える。
Process.spawnIO.popenOpen3も同様。
単に外部プロセス起動をして終了を待ちたいならKernel#systemが手軽でいいんじゃないだろうか。
そのプロセスの標準出力がほしいならKernel#`、もうちょっといろいろやりとりしたいならProcess.spawnIO.popenOpen3がいいだろう。

_ forkはプロセスコピーが生じるので、fork+exec系の処理は明らかにメモリの無駄遣いであるが、Windowsではそのようなことが生じないのでハッピーである。
『なるほどUnixプロセス』ではposix-spawnというgemが紹介されているが、これはWindowsでも動作し、Windowsの場合はオリジナルのKernel#spawnをそのまま実行するようになっている。
ところで、posix-spawnは拡張ライブラリ部分がビルドできないUnix環境がいっぱいあるようなので、真面目にextconf.rbでコンパイル条件をチェックして、対応しない環境についてはWindowsのようにRubyにまかせて一応動くようにする、っていうコードに修正すべきではないだろうか。

不定期連載「『なるほどUnixプロセス』で学ぶWindows版Rubyの基礎」おわりに

_ というわけで、長きに渡ったこの不定期連載もこれにて終了である。
付き合ってくれた皆さん、ありがとう。
アクセスログ見てるとなんかどんどん脱落していったようだが :)

_ Unixにおけるfork(2)は面白便利な機構ではあるが、実際に自プロセスをコピーしたプロセスを生成できないと困って死ぬ、という場面はそんなに多くはない。
一番うまくこの機構を活用しているのが、『なるほどUnixプロセス』の付録3で紹介されているpreforkサーバモデルだと思われる。
が、スレッドがちゃんと活用できるならこれはスレッドで書け、その場合はプロセス全体でなく必要な処理部分のみが複製・実行されるので効率もよい。
また、preforkサーバモデル以外でfork(2)を使う場面の多くは、実は別プロセスの起動の前段階であり、この用途でfork(2)を使うのはオーバーヘッドが非常に大きいのも『なるほどUnixプロセス』で示されているとおりである。

_ というわけで、Windowsのように、プロセスコピーは行わず、いきなり別プロセスを自プロセスから分離して起動できるというモデルは、ユースケース的にはそれなりに優れたものと言える。
このモデルの弱点であるpreforkサーバが作れないという点についても、Windowsでは早くからスレッド機構を活用することで対応している。
Unix側の仕組みが劣っているとかダメだとか言うつもりはないが、後発のWindowsは、後発であるがゆえに、Unixを始めとする各OSにおける知見を踏まえた上で、また別の優れた仕組みを提供している、といえるだろう。

_ ただ、ことRubyにおいては、Ruby自体がUnixにべったりであるため、どうしてもWindows版Rubyはそれに追従する形で実装せざるを得ず、必ずしも高効率で便利な仕組みとまではいえないものになっている。
将来的にこのあたりが改善され、よりWindows環境に強いRubyとなっていくことを期待してやまない。

_ とまれ、現状でも、今まで示したように、Windows版Rubyは、プロセス周りという非常に環境依存性の高い場面でも、それなりのレベルでスクリプトレベルでの互換性を提供している。
普段Unix上でRubyを使っている皆さんも、どーしても必要な場面(ないでしょ?)以外ではKernel#forkを使わず、普通の、つまりポータブルなプロセス生成メソッド群を使用するように心がけて頂けると幸いである。


被捕捉アンテナ類
[Ant] [Antenna-Julia] [Rabbit's Antenna] [Ruby hotlinks]