代码之家  ›  专栏  ›  技术社区  ›  Adrian

当程序等待stdin时,为什么open4不能从stdout读取?

  •  2
  • Adrian  · 技术社区  · 15 年前

    我正在使用 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 回复  |  直到 9 年前
        1
  •  2
  •   Adrian    15 年前

    我需要改变 test1.rb 对此。我不知道为什么。

    print 'hi.' # 3 characters
    $stdout.flush
    $stdin.read(1) # block
    
        2
  •  2
  •   Community CDub    8 年前

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

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

    对于其他文件,a 脸红 在其他场合也会这样做,比如 ftell .

    如果将stdout设置为无缓冲模式( $stdout.sync = true )将不使用缓冲区。

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

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

        3
  •  1
  •   OmniBus    15 年前

    我不是工艺专家。

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