为什么对于STDOUT而言,IO :: WaitReadable的提升方式与STDERR不同?

Ale*_*ski 5 ruby io pipe popen

鉴于我希望测试从长命令非阻塞读,我创建了下面的脚本,保存为long,使其可执行文件chmod 755,并把它放在我的道路(保存~/bin/long在那里~/bin是我的路径).

我在ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin11.0.0]使用RVM默认编译的*nix变体上.我不使用Windows,因此如果你这样做,我不确定测试脚本是否适合你.

#!/usr/bin/env ruby

3.times do
  STDOUT.puts 'message on stdout'
  STDERR.puts 'message on stderr'
  sleep 1
end
Run Code Online (Sandbox Code Playgroud)

为什么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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

我假设您将require 'open3'在测试任一功能之前.

为什么IO::WaitReadableSTDOUT的提升方式与STDERR不同?

如果您拥有它们,使用其他方法启动子进程的变通方法也很受欢迎.

Cas*_*per 4

在大多数操作系统中,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
Run Code Online (Sandbox Code Playgroud)

你会看到差异。

您可能还想检查“了解 Ruby 和操作系统 I/O 缓冲”。