ruby - 为什么 IO::WaitReadable 对于 STDOUT 的引发方式与 STDERR 的引发方式不同?

标签 ruby io pipe popen

考虑到我想测试一个长命令的非阻塞读取,我创建了以下脚本,将其保存为 long,并使用 chmod 755 使其可执行,并将其放在我的路径中(另存为 ~/bin/long,其中 ~/bin 在我的路径中)。

我在使用 RVM 默认值编译的 ruby 1.9.2p290(2011-07-09 修订版 32553)[x86_64-darwin11.0.0] 的 *nix 变体。我不使用 Windows,因此不确定测试脚本是否适合您。

#!/usr/bin/env ruby

3.times do
  STDOUT.puts 'message on stdout'
  STDERR.puts 'message on stderr'
  sleep 1
end

为什么 long_err 会生成每个 STDERR 消息,因为它是由“long”打印的

def long_err( bash_cmd = 'long', maxlen = 4096)
  stdin, stdout, stderr = Open3.popen3(bash_cmd)
  begin
    begin
      puts 'err -> ' + stderr.read_nonblock(maxlen)
    end while true
  rescue IO::WaitReadable
    IO.select([stderr])
    retry
  rescue EOFError
    puts 'EOF'
  end
end

long_out 在打印所有 STDOUT 消息之前一直处于阻塞状态?

def long_out( bash_cmd = 'long', maxlen = 4096)
  stdin, stdout, stderr = Open3.popen3(bash_cmd)
  begin
    begin
      puts 'out -> ' + stdout.read_nonblock(maxlen)
    end while true
  rescue IO::WaitReadable
    IO.select([stdout])
    retry
  rescue EOFError
    puts 'EOF'
  end
end

我假设您在测试任一函数之前需要“open3”

为什么 IO::WaitReadable 对 STDOUT 和 STDERR 的引发不同?

使用 other ways to start subprocesses 的解决方法如果您拥有它们,我们也将不胜感激。

最佳答案

在大多数操作系统中,STDOUT 是缓冲的,而 STDERR 不是。 popen3 所做的基本上是在您启动的可执行文件和 Ruby 之间打开一个管道。

任何处于缓冲模式的输出都不会通过此管道发送,直到:

  1. 缓冲区已满(因此强制刷新)。
  2. 发送应用程序退出(到达 EOF,强制刷新)。
  3. 流被显式刷新。

STDERR 未被缓冲的原因是通常认为错误消息立即出现很重要,而不是通过缓冲来提高效率。

因此,了解这一点后,您可以像这样使用 STDOUT 模拟 STDERR 行为:

#!/usr/bin/env ruby

3.times do
  STDOUT.puts 'message on stdout'
  STDOUT.flush 
  STDERR.puts 'message on stderr'
  sleep 1
end

你会看到不同之处。

您可能还想检查“Understanding Ruby and OS I/O buffering”。

关于ruby - 为什么 IO::WaitReadable 对于 STDOUT 的引发方式与 STDERR 的引发方式不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7127603/

相关文章:

Ruby Watir 找不到 firefox 二进制文件

ruby-on-rails - 新项目可以使用 Rails 3.1 吗?是不是很难转换过来?

ruby - 使用 rspec 测试 ruby​​ 的文件名并使用 while gets 测试 STDIN

ruby-on-rails - 在 AASM 中自动更改状态的最佳方法是什么

c - 如果我们不关闭管道 : Linux/C 中使用过的一端会发生什么

linux - linux内核在哪里保存写入管道的数据

java - Android 使用 URI 删除文件不起作用

c - 如何阻止读取系统调用

无法在 linux 中使用 fcntl 切换到阻塞模式

Linux 管道和重定向输出