2

我正在使用open4gem 并且在从生成的进程标准输出中读取时遇到问题。我有一个红宝石程序,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

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

4

3 回答 3

2

我需要改变test1.rb这个。我不知道为什么。

print 'hi.' # 3 characters
$stdout.flush
$stdin.read(1) # block
于 2010-07-15T23:02:03.473 回答
2

默认情况下,您print写入标准输出或其他文件的所有内容都会写入 Ruby 的缓冲区(或标准 C 库,位于 Ruby 之下)。如果发生以下事件之一,缓冲区的内容将转发给操作系统:

  • 缓冲区已满。
  • 你关闭标准输出。
  • 你打印了一个换行序列(`\n')
  • flush明确地打电话。

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

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

默认情况下,stderr 是无缓冲的。做缓冲的原因是效率:在一个缓冲区中聚合输出数据可以节省很多系统调用(对操作系统的调用)。系统调用非常昂贵:它们需要数百甚至数千个 CPU 周期。用一点代码和用户空间中的一些缓冲区来避免它们会导致很好的加速。

关于缓冲的好读物:为什么 printf 在调用后不刷新,除非换行符在格式字符串中?

于 2014-10-31T13:09:01.143 回答
1

我不是过程方面的专家。

从我第一次看到 API 文档开始,使用 open4 的顺序是这样的:首先发送文本到标准输入,然后关闭标准输入,最后从标准输出读取文本。

所以。你可以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
于 2010-07-12T03:10:42.903 回答