Я хочу передать блок кода в основном процессе дочернему процессу, чтобы он работал одновременно. Я также хочу иметь PID порожденного дочернего процесса, чтобы я мог отслеживать и при необходимости убивать его.

Вы можете использовать метод ядра fork. Вот пример:
#!/usr/bin/env ruby
puts "This is the master process."
child_pid = fork do
puts "This is the child process"
exit
end
puts "The PID of the child process is #{child_pid}"
Метод fork возвращает PID процесса, который он разветвляет, и выполняет любой код в переданном блоке. Как и обычные блоки Ruby, он сохраняет привязки родительского процесса.
Хорошая идея - сделать ваш разветвленный процесс exit.
@Vadim Я думаю, что это особенность, а не ошибка.
Я немного сбит с толку насчет звонка exit - зачем (или когда) он нужен?
@skwisgaar exit необходим для обеспечения завершения разветвленного процесса. В противном случае вы можете получить зомби или сиротские процессы. Подробнее на: stackoverflow.com/a/20689837/3784008. Краткое объяснение: вызовите exit внутри вашего разветвленного процесса после того, как он завершит выполнение своего кода, или новый процесс ruby, который был порожден, продолжит работу в фоновом режиме.
exit с кодом по умолчанию не требуется с этой формой вилки, поскольку «блок выполняется в подпроцессе, а подпроцесс завершается со статусом ноль». Чтобы избежать создания зомби, вам нужно либо Process.wait, либо Process.detach в родительском процессе. ruby-doc.org/core-2.2.3/Kernel.html#method-i-forkФорк ядра отличается от Process.fork? Если да, то как?
В дополнение к отличному ответу Криса, не забудьте вызвать Process.wait от своего мастера, чтобы пожать ваш дочерний процесс, иначе вы оставите зомби позади.
Пример, как запрошено в комментариях:
pid = Process.fork do
puts "child, pid #{Process.pid} sleeping..."
sleep 5
puts "child exiting"
end
puts "parent, pid #{Process.pid}, waiting on child pid #{pid}"
Process.wait
puts "parent exiting"
Милый, это был отличный совет.
Где и как бы вы поместили Process.wait в принятый ответ выше?
Обратите внимание, что Process.wait без аргумента ожидает дочернего Любые, поэтому в более общем случае этот фрагмент кода выйдет из родительского, даже если указанный выше конкретный дочерний процесс не завершится. В более точной версии вместо этого будет сказано Process.wait(pid).
Есть ли независимый от платформы способ сделать это (т.е. без fork, поскольку это только в Unix)?
Согласимся в Process.waitall. Родитель будет ждать выхода дочерних ВСЕ.
Если вам нравится использовать потоки, а не процессы, то что-то вроде этого май будет немного более масштабируемым для более чем одной вилки:
def doit(x)
sleep(rand(10))
puts "Done... #{x}"
end
thingstodo = ["a","b","c","d","e","f","g"]
tasklist = []
# Set the threads going
thingstodo.each { |thing|
task = Thread.new(thing) { |this| doit(this) }
tasklist << task
}
# Wait for the threads to finish
tasklist.each { |task|
task.join
}
См. Превосходные комментарии и ссылки Джона Топли ниже, касающиеся модели выполнения Ruby и ее ограничений.
Только что отредактировал, чтобы исправить явную ошибку (нет назначения задачи) и следовать совету @ (Джейсона Кинга).
Предположительно, это зеленые потоки, а не правильные потоки ОС?
Прочтите это о Ruby 1.9: igvita.com/2008/11/13/concurrency-is-a-myth-in-ruby
Должно быть: Thread.new(thing) { |it| doit(it) }, потому что thing сбрасывается на каждой итерации, поэтому нет гарантии, что правильный поток получит правильный thing.
В версии 1.9 вы можете использовать команду Process.spawn. См. Также http://en.wikibooks.org/wiki/Ruby_Programming/Running_Multiple_Processes
При использовании Ruby следует помнить, что не все вещи работают точно так же в Windows и * nix. Иногда они полностью не реализованы в Windows, поэтому используйте их на свой страх и риск.