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)

线程器.rb

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

一个 ruby​​ 脚本是一个简单的微调器,它每秒都会输出到标准输出。

另一个用于运行该脚本,我想在数据进入时捕获它。所以我希望流从标准输出非阻塞读取。

我似乎无法让它发挥作用。我想我O_NONBLOCK正确设置了 fctnl 标志,但也许我没有。

4

1 回答 1

6

您的代码运行良好。你只缺少一件,那就是刷新你的输出缓冲区threader

问题是 STDOUT 几乎总是被缓冲,在这种情况下,除非明确告知,否则缓冲区不会被刷新,直到线程退出之后。

这就是为什么读者什么都看不到的原因,然后当线程退出并且 STDOUT 被刷新时,它会突然得到一个输出。

所以这个测试的简单修复是:

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

但是请注意,由于您正在使用 NONBLOCK 阅读,您的阅读器将忙于循环(!)消耗 100% 的 CPU。为了防止busylooping,您真正应该做的是在读取之前等待传入数据。

这可以通过以下方式完成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 回答