我正在使用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
它永远只是坐在那里而不打印任何东西。为什么会发生这种情况,我该怎么办才能阻止它呢?
答案 0 :(得分:2)
我需要将test1.rb
更改为此。我不知道为什么。
print 'hi.' # 3 characters
$stdout.flush
$stdin.read(1) # block
答案 1 :(得分:2)
默认情况下,将print
stdout或另一个文件的所有内容写入Ruby的缓冲区(或标准C库,位于Ruby下)。如果发生以下事件之一,则缓冲区的内容将转发到操作系统:
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