Должен ли Process.fork влиять на файл io в Ruby? - PullRequest
1 голос
/ 10 марта 2012

Я использовал 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 Ответ

4 голосов
/ 11 марта 2012

Когда вы выполняете разветвление, дочерний процесс будет содержать клон открытого файла родителя, с любыми данными, ожидающими в своем буфере. Когда ребенок выходит, он сбрасывает эти данные и закрывает свой открытый файл. Это не влияет на открытые файлы родителей или братьев и сестер, но, поскольку они все отображаются в одно и то же ядро, все данные поступают в один и тот же выходной файл.

В первый раз через fork нет ожидающих результатов, так что потомок не будет ничего писать, когда он существует. Во второй раз есть ожидание «0 \ n», которое будет записано при выходе, в следующий раз буферизация «0 \ n1 \ n» и т. Д. Разветвленные процессы могут не завершиться в порядке их создания ( они асинхронные), следовательно, ваши перемешанные результаты.

Вилы сохраняют открытые файлы и сокеты, поэтому нужно быть осторожным, чтобы тщательно управлять ими.

Вероятно, вы можете исправить это поведение, сказав 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...