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でスレッドを切り替える。とされているかなんとなくわかった気がする。