Подтвердить что ты не робот

Возврат данных из разветвленных процессов

Если я делаю

Process.fork do 
  x 
end 

как я могу узнать, что возвращает x (например, true/fase/string)?

(Запись в файл/базу данных не является параметром...)

4b9b3361

Ответ 1

Я завернул все решения, которые я нашел на этом пути (некоторые другие проблемы, такие как пользователь, выходящий из + буферов) в рубиновый параллельный жемчуг. Теперь это так же просто:

results = Parallel.map([1,2,3],:in_processes=>4) do |i|
  execute_something(i)
end

или

results = Parallel.map([1,2,3],:in_threads=>4) do |i|
  execute_something(i)
end

Ответ 2

На самом деле нам просто пришлось справиться с этой проблемой в Rails изоляции тестирования. Я разместил об этом несколько в своем блоге.

В принципе, то, что вы хотите сделать, - это открыть канал в родительском и дочернем объектах и ​​записать его в канал. Вот простой способ запустить содержимое блока в дочернем процессе и вернуть результат:

def do_in_child
  read, write = IO.pipe

  pid = fork do
    read.close
    result = yield
    Marshal.dump(result, write)
    exit!(0) # skips exit handlers.
  end

  write.close
  result = read.read
  Process.wait(pid)
  raise "child failed" if result.empty?
  Marshal.load(result)
end

Затем вы можете запустить:

do_in_child do
  require "some_polluting_library"
  SomePollutingLibrary.some_operation
end

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

Также обратите внимание, что здесь много деталей (read.close, Process.wait2(pid)) - это главным образом служебные данные, поэтому, если вы используете это много, вы, вероятно, должны переместить это в библиотеку утилиты, которую вы можете повторно использовать.

Наконец, обратите внимание, что это не будет работать в Windows или JRuby, так как они не поддерживают forking.

Ответ 3

Спасибо за все ответы, я получил свое решение и все еще нужно посмотреть, как обращаться с не-forking-средами, но на данный момент он работает:)

read, write = IO.pipe
Process.fork do
  write.puts "test"
end
Process.fork do
  write.puts 'test 2'
end

Process.wait
Process.wait

write.close
puts read.read
read.close

вы можете увидеть это в действии @parallel_specs Плагин Rails

Ответ 4

Да, вы можете создать подпроцесс для выполнения блока внутри.

Я рекомендую драгоценный камень aw:

Aw.fork! { 6 * 7 } # => 42

Конечно, он предотвращает побочные эффекты:

arr = ['foo']
Aw.fork! { arr << 'FUU' } # => ["foo", "FUU"]
arr # => ["foo"]

Ответ 5

Согласно документации:

Если задан блок, этот блок запускается в подпроцессе, а подпроцесс завершается со статусом нуля.

Итак, если вы вызываете его с помощью блока, он возвращает 0. В противном случае он функционирует в основном так же, как системный вызов fork() в Unix (родитель получает PID нового процесса, ребенок получает nil).

Ответ 6

Связь между двумя процессами Unix - это, прежде всего, код возврата и ничего больше. Тем не менее, вы можете открыть filedescriptor между двумя процессами и передать данные между процессами над этим filedescriptor: это обычный путь к Unix-каналу.

Если вы будете передавать значения Marshal.dump() и Marshal.load(), вы можете легко передать объекты Ruby между этими Ruby-процессами.

Ответ 7

Вы можете использовать разделяемую память, чтобы сделать это, если ребенок просто должен быть небольшим фрагментом кода ruby. Будет работать следующее:

str = 'from parent'

Thread.new do
  str = 'from child'
end

sleep(1)

puts str    # outputs "from child"

Concurrency может быть довольно сложным, и доступ к общей памяти таким образом является большой частью причины - в любое время, когда у вас есть переменная, а другой процесс может изменить ее из-под вас, вы должны быть очень С осторожностью. Альтернативно, вы можете использовать трубу, которая является более громоздкой, но, вероятно, более безопасной для любого, но самого тривиального кода, а также может использоваться для запуска любой произвольной команды. Вот пример, прямо из rdoc для IO.popen:

f = IO.popen("uname")
p f.readlines     # outputs "Darwin", at least on my box  :-)