それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

RubyはIO.pipeを使えば、パイプを作ることが出来る

IO.pipeを使えば、パイプを作ることが出来る

パイプを作ると楽しい。

o,i = IO.pipe
100.times{ i.puts :test }
100.times{ puts o.gets }

これだけ

Pipeを使うと何が便利か。スレッドをブロック出来る

loop{ p o. gets }

で i.puts を待つことが出来る。

どういうことかというと

IO.pipeはブロックする?

>> input.puts "aaaaaaaaa" #=> nil
>> input.puts "aaaaaaaaa" #=> nil
>> input.puts "aaaaaaaaa" #=> nil
>> out.gets #=> "aaaaaaaaa\n"
>> out.gets #=> "aaaaaaaaa\n"
>> out.gets #=> "aaaaaaaaa\n"
>> out.gets
#待つ

こういうことです。3行書きだしたので、3行読み込める。4行目を読み込んだ時点で、パイプは空。なので、データが来るのを待ちます。

まってると、irb側からは手出しができないです。どうするのか?threadや、drubyをつかいます。threadを使って別スレッドから4行目を書き込んだり、drubyを使って別プロセスから4行目を書き込みます。

o,i = IO.pipe
Thread.start{loop{ i.puts "aaaaaaaaa" }}
100.times{ puts o.gets }
>> out.gets #=> "aaaaaaaaa\n"
>> out.gets #=> "aaaaaaaaa\n"
>> out.gets #=> "aaaaaaaaa\n"
>> out.gets #=> "aaaaaaaaa\n"
#...etc

drubyの場合、なんにつかうの?ネットワークパイプです。

たとえば、drbを読み込んで、druby経由で、ネットワーク越しにIOをやり取りできる。
まともにやると、ncコマンドやポート制御が必要だったりする。
でもRubyならdrubyと、IO.pipeで即決

受信側
o,i = IO.pipe
s =DRb.start_service( "druby://localhost:12345", i)
loop{ p o. gets }
送信側
i= DRbObject.new_with_uri('druby://localhost:12345') 
100.times{ i.puts :test }

IO.pipeとdrb/threadの組み合わせは便利。

これで、スレッドを簡単に扱えるし、IOでパイプを扱うこともできる。そしてネットワークでパイプを扱うこともできる。便利ね。

ちなみに、readについて

o.readは i.closeを待つ

IOなので、readコマンドはEOFを待つ。つまり、i.closeでEOFが送られない限りo.readはブロックされる。


このあたりのブロックの仕組みを見ているとruby のプリエンプションのthreadがどうしてIOでスレッドを切り替える。とされているかなんとなくわかった気がする。