Process.fork应该影响Ruby中的文件io吗?

时间:2012-03-10 07:03:51

标签: ruby fork

我一直在可观察对象中使用Process.fork,但发现它干扰了观察者对象的文件输出的输出。

当我注释掉Process行时,输出的文件包含16行,每行编号为0-15。但是,当取消注释时,该文件包含136行0-15之间的无序数字。无论Process是否被注释掉,都会在屏幕上显示正确的数字。

是否部分预期此行为,或者这是一个错误?有没有人有任何想法如何解决这个问题?

下面的代码重现了这个问题,并通过剥离原始代码创建,直到有足够的证据来证明这个问题。使用Process.fork的最初原因是创建了几个流程以加快处理速度。

require 'observer'

class Recorder
  def initialize(notifier, filename)
    notifier.add_observer(self)
    @save_file =  File.open(filename, 'w')
    @i = 0
  end

  def update
    puts @i
    @save_file.puts @i
    @i += 1
  end


  def stop
    @save_file.close
  end
end


class Notifier
  include Observable

  def run
    16.times do 
      # When the following two Process lines are uncommented,
      # the file output from the Recorder above is erratic
      Process.fork {exit}
      Process.wait

      changed
      notify_observers
    end
  end
end


notifier = Notifier.new
recorder = Recorder.new(notifier, 'test.data')

notifier.run
recorder.stop

1 个答案:

答案 0 :(得分:4)

当你进行fork时,子进程将包含父进程的打开文件的克隆,其缓冲区中的任何数据都是挂起的。当孩子退出时,它将刷新此数据并关闭其打开的文件。这不会影响父节点或兄弟节点的打开文件,但由于它们都映射到同一个内核fd,因此所有数据都会转到同一个输出文件。

第一次通过fork时,没有挂起的输出,所以当孩子存在时,孩子不会写任何东西。第二次,有一个“0 \ n”挂起它将在退出时写入,下一次,有“0 \ n1 \ n”缓冲等等。分叉的进程可能不会按照它们创建的顺序退出(他们是异步的,因此你的结果很混乱。

Forks保留打开的文件和套接字,因此需要小心谨慎管理它们。

你可以通过告诉ruby在每次写入时刷新输出而不是缓冲来修复这种行为。

class Recorder
  def initialize(notifier, filename)
    notifier.add_observer(self)
    @save_file =  File.open(filename, 'w')
    @save_file.sync = true # don't buffer this file
    @i = 0
  end
end