5

だから私は次のコードを持っています:

リーダー.rb

require 'open4'

def streamer(stdout)
  begin
    loop do
      data = stdout.read_nonblock(8)
      print data
    end
  rescue Errno::EAGAIN
    retry
  rescue EOFError
    puts 'End of file'
  end
end
pid, stdin, stdout, stderr = Open4::popen4 "ruby threader.rb"
stdout.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
streamer(stdout)

threader.rb

10.times do
  $stdout.puts "test"
  sleep 1
end

1 つの ruby​​ スクリプトは、毎秒 stdout に出力する単純なスピナーです。

もう1つはそのスクリプトを実行するためのもので、データが入ってくるとキャプチャしたいので、ストリームがstdoutノンブロッキングから読み取られるようにします。

私はこれを機能させることができないようです。O_NONBLOCKfctnlフラグを適切に設定していると思いますが、おそらくそうではありません。

4

1 に答える 1

6

あなたのコードは正常に動作しています。欠落しているのは 1 つだけであり、それは の出力バッファーをフラッシュしていますthreader

問題は、STDOUT がほとんど常にバッファリングされることです。この場合、明示的に指示されない限り、スレッダーが終了するまでバッファはフラッシュされません。

そのため、リーダーには何も表示されず、スレッドが終了して STDOUT がフラッシュされると、突然出力が急増します。

したがって、このテストの簡単な修正は次のとおりです。

10.times do
  $stdout.puts "test"
  $stdout.flush
  sleep 1
end

ただし、NONBLOCK を使用して読み取りを行っているため、リーダーはビジー ループ (!) で 100% の CPU を消費することに注意してください。ビジーループを防ぐために実際にすべきことは、データを読み取る前に受信データを待つことです。

これは次の方法で実行できますIO.select

...
loop do
  IO.select([stdout]) # <- waits for data (any data, even 1 byte)
  data = stdout.read_nonblock(8)
  print data
end  
...
于 2012-05-02T07:41:18.867 に答える