2章.Hello, dRuby (その1)
「2章.Hello, dRuby」に入りました。まずは「Hello, World.」ですね。
この実験では二つのプロセスが登場します。一つは文字列を印字するサーバ、もう一つは印字サーバを利用して「Hello, World.」を putsするクライアントです。2.1 Hello, World.
まずはサーバー側となるputs00.rbの方からソースコード(リスト2.1)を、順に見ていくことにします。私はRubyをちゃんと勉強していないので、ついでにRubyのことも詳しめに見てみることにしてみようと思います。
require 'drb/drb'
Cでいうincludeみたいなもののようです。使いたいモジュール(モジュールと言う呼称でいいのかはわからないが)をこれで含めると、インタプリタがそっちを先に読みに行って、そこに定義されているものが使えるようになる。と言う感じに理解しておきます。
class Puts
classでクラスを定義できます。
def initialize(stream=$stdout)
defはメソッドを定義できるようです。で、initializeって名前のメソッドはコンストラクタのようです。
$で始まるものはグローバルな変数です。なので$stdoutはグローバル変数のうちのひとつです。標準出力を指し示す組み込み変数(あらかじめ定義されている変数)のようです。
@stream = stream
Rubyでは、@がついてるやつはインスタンス変数になります。ここでは引数のstreamをインスタンス変数の@streamに代入してるってことですね。
uri = ARGV.shift
うごご、わからん。でもなんとなく想像はつく。調べてみると、ARGVはどうやらコマンドライン引数が入ってくる配列のようです。(Cのように、0番目にプログラム名が入ってきたりはしません。)で、shiftは、先頭の一要素を取るメソッドのようです。shiftが実行されると、先頭の要素は取り除かれ、他の要素はひとつずつ詰められるようです。ほうほう。puts00は、実行時にコマンドライン引数の先頭にURIを指定してもらう仕様であるということですね。
DRb.start_service(uri, Puts.new)
ついにきましたDRb。解説文を見てみると
3. サービスの場所を示す名前であるURIと、URIに関連付けるオブジェクトを指定して dRubyのサービスを開始します。これによってリクエストを待機するスレッドも準備されます。URIに関しては後述します。2.1.1 印字サーバ
とあります。にゃるほど。「リクエストを待機するスレッドも準備されます。」と言うところが重要そうだな思いつつ次のステートメントを見てみます。
sleep
これはスレッドを止めるやつのようです。むむむ、止まっちゃうんだよね。で、このプログラムはsleepが最後の行だからもし復帰したら終わっちゃうんだよね。
ちなみにスレッドとは、処理を実行する単位とか、処理の実行者を指したり、処理の流れそのものを指したりします。プロセス内の処理を実際に実行しているのはスレッドになります。どこかから起動されたRubyのプロセスは必ずひとつ以上のスレッドを持ちます。最初に立ち上げられるのはメインスレッドと言うみたいです。同プロセス内のスレッドは、プロセス空間(メモリの場とか)を共有します。Rubyでのマルチスレッドの話はまた後で出てくるみたいなので楽しみにしておきます。
さて、ここのsleepは「スクリプトが終了してしまわないように、メインスレッドをsleepさせます。」とあります。
そもそもsleepってどこのメソッドなのかなあ。Kernelモジュールのsleepってやつが呼ばれてるのかしら。。KernelモジュールはWindowsだと多分kernel32.dllをロードして使えるようにしてるのかなあ?...っと予想通りwin32.cでやっていました。windows.hをincludeしてるWin32SDKプログラミングですね。濃いのでRuby本体のソースはこれ以上追いかけないようにして。。。。組み込み関数のsleepの説明を見てみると、
sec 秒だけプログラムの実行を停止します。sec には浮動小数点数も指定できます。sec が省略された場合、他スレッドからの Thread#run などで明示的に起こさない限り永久にスリープします。戻り値は実際に停止していた秒数(整数)です。
とあります。で、どこからでも呼べると。呼んだら、それを実行していたスレッドが止まると。ここでは引数を指定していないので、起こされない限り永遠に止まっていると言うことですね。で、もし起こされてもこのプログラムはsleepが最後の行だからそのまま終わると。ふむふむ。
じゃあ、やっぱりDRb.start_serviceで新しいスレッドを起こしていないと何も出来ないはずです。ちょっとだけみてみるかな、難しかったらあきらめよう。。と、start_serviceメソッドの中では、DRbServerをnewしてるな、でDRbServerのinitializeの中で
@thread = run
としている。これかなあ。runをみてみると
def run
Thread.start do
begin
while true
main_loop
end
ensure
@protocol.close if @protocol
kill_sub_thread
end
end
end
うごご、tabと半角スペースが雑じっててなんだかインデントがわからぬデス。。。っと、それはさて置き、RubyのThreadはstartメソッドにブロックを渡せるんですね。runメソッドではThread.startで新スレッドを生成、実行し、そのオブジェクトが勝手に返却されてると。で、そのスレッドの中のブロックはぐるぐる回ってるmain_loopがいる感じですね。ほうほう。とりあえず要求を受け付けるスレッドは作られてそうだということが確認できたので、puts00については満足。
まだサーバー側しかみていませんが、ソースコードが入ると長くなる予感。この調子でどこまで行けるか。。と一抹の不安を覚えつつ続きはまた後日。

