我一直在可观察对象中使用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
答案 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