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

发布于 2024-09-08 16:53:19 字数 455 浏览 6 评论 0原文

我正在使用 open4 gem,但从生成的进程标准输出读取时遇到问题。我有一个 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

它永远坐在那里,没有打印任何东西。为什么会发生这种情况?我可以采取什么措施来阻止这种情况?

I am using the open4 gem and having problems reading from the spawned processes stdout. I have a ruby program, test1.rb:

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

And another ruby program in the same directory, test2.rb:

require 'open4'

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

When I run the second program:

$ ruby test2.rb

It just sits there forever without printing anything. Why does this happen, and what can I do to stop it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

尘世孤行 2024-09-15 16:53:19

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

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

I needed to change test1.rb to this. I don't know why.

print 'hi.' # 3 characters
$stdout.flush
$stdin.read(1) # block
二货你真萌 2024-09-15 16:53:19

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

  • 缓冲区已满。
  • 您关闭标准输出。
  • 您已打印换行符序列 (`\n')
  • 您显式调用 flush

对于其他文件,也会在其他情况下执行flush,例如ftell

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

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

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

By default, everything that you printto stdout or to another file is written into a buffer of Ruby (or the standard C library, which is underneath Ruby). The content of the buffer is forwarded to the OS if one of the following events occurs:

  • The buffer gets full.
  • You close stdout.
  • You have printed a newline sequence (`\n')
  • You call flush explicitly.

For other files, a flush is done on other occasions, too, like ftell.

If you put stdout in unbuffered mode ($stdout.sync = true), the buffer will not be used.

stderr is unbuffered by default.
The reason for doing buffering is efficiency: Aggregating output data in a buffer can save many system call (calls to operating system). System calls are very expensive: They take many hundreds or even thousands of CPU cycles. Avoiding them with a little bit of code and some buffers in user space results in a good speedup.

A good reading on buffering: Why does printf not flush after the call unless a newline is in the format string?

2024-09-15 16:53:19

我不是流程方面的专家。

从我第一眼看到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

I'm not an expert in process.

From my first sight of API document, the sequence of using open4 is like this:
first send text to stdin, then close stdin and lastly read text from stdout.

So. You can the test2.rb like this

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文