为什么程序在等待stdin时无法从stdout读取open4?

时间:2010-07-12 01:44:43

标签: ruby stdout iostream io open4

我正在使用open4 gem并且从生成的进程stdout中读取时出现问题。我有一个ruby程序,test1.rb

print 'hi.' # 3 characters
$stdin.read(1) # block

同一目录中的另一个ruby程序test2.rb

require 'open4'

pid, stdin, stdout, stderr = Open4.popen4 'ruby test1.rb'
p stdout.read(2) # 2 characters

当我运行第二个程序时:

$ ruby test2.rb

它永远只是坐在那里而不打印任何东西。为什么会发生这种情况,我该怎么办才能阻止它呢?

3 个答案:

答案 0 :(得分:2)

我需要将test1.rb更改为此。我不知道为什么。

print 'hi.' # 3 characters
$stdout.flush
$stdin.read(1) # block

答案 1 :(得分:2)

默认情况下,将print stdout或另一个文件的所有内容写入Ruby的缓冲区(或标准C库,位于Ruby下)。如果发生以下事件之一,则缓冲区的内容将转发到操作系统:

  • 缓冲区已满。
  • 你关闭stdout。
  • 您已打印换行符序列(`\ n')
  • 您明确致电flush

对于其他文件,flush也会在其他场合完成,例如ftell

如果将stdout置于无缓冲模式($stdout.sync = true),则不会使用缓冲区。

默认情况下,

stderr是无缓冲的。 进行缓冲的原因是效率:在缓冲区中聚合输出数据可以节省许多系统调用(对操作系统的调用)。系统调用非常expensive:它们需要数百甚至数千个CPU周期。用一点代码和用户空间中的缓冲区来避免它们会带来很好的加速。

关于缓冲的好读物:Why does printf not flush after the call unless a newline is in the format string?

答案 2 :(得分:1)

我不是流程专家。

从我第一次看到API文档开始,使用open4的顺序如下: 首先将文本发送到stdin,然后关闭stdin,最后从stdout读取文本。

因此。您可以test2.rb喜欢这个

require 'open4'

pid, stdin, stdout, stderr = Open4.popen4 'ruby test1.rb'
stdin.puts "something" # This line is important
stdin.close # It might be optional, open4 might close itself.
p stdout.read(2) # 2 characters