考虑到我想测试一个长命令的非阻塞读取,我创建了以下脚本,将其保存为 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 之间打开一个管道。
任何处于缓冲模式的输出都不会通过此管道发送,直到:
- 缓冲区已满(因此强制刷新)。
- 发送应用程序退出(到达 EOF,强制刷新)。
- 流被显式刷新。
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/