Как вы создаете дочерний процесс в Ruby?

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

Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
39
0
39 693
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Вы можете использовать метод ядра 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.

При использовании Ruby следует помнить, что не все вещи работают точно так же в Windows и * nix. Иногда они полностью не реализованы в Windows, поэтому используйте их на свой страх и риск.

Daemin 22.11.2008 20:33

@Vadim Я думаю, что это особенность, а не ошибка.

Chris Lloyd 16.02.2009 02:57

Я немного сбит с толку насчет звонка exit - зачем (или когда) он нужен?

skwisgaar 30.10.2016 22:55

@skwisgaar exit необходим для обеспечения завершения разветвленного процесса. В противном случае вы можете получить зомби или сиротские процессы. Подробнее на: stackoverflow.com/a/20689837/3784008. Краткое объяснение: вызовите exit внутри вашего разветвленного процесса после того, как он завершит выполнение своего кода, или новый процесс ruby, который был порожден, продолжит работу в фоновом режиме.

anothermh 04.02.2017 03:00
exit с кодом по умолчанию не требуется с этой формой вилки, поскольку «блок выполняется в подпроцессе, а подпроцесс завершается со статусом ноль». Чтобы избежать создания зомби, вам нужно либо Process.wait, либо Process.detach в родительском процессе. ruby-doc.org/core-2.2.3/Kernel.html#method-i-fork
artm 21.03.2018 15:01

Форк ядра отличается от Process.fork? Если да, то как?

shevy 17.06.2020 14:05

В дополнение к отличному ответу Криса, не забудьте вызвать 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"

Милый, это был отличный совет.

Chris Lloyd 23.11.2008 12:15

Где и как бы вы поместили Process.wait в принятый ответ выше?

iamtoc 12.10.2012 03:29

Обратите внимание, что Process.wait без аргумента ожидает дочернего Любые, поэтому в более общем случае этот фрагмент кода выйдет из родительского, даже если указанный выше конкретный дочерний процесс не завершится. В более точной версии вместо этого будет сказано Process.wait(pid).

sameers 21.11.2014 21:10

Есть ли независимый от платформы способ сделать это (т.е. без fork, поскольку это только в Unix)?

Fund Monica's Lawsuit 17.12.2015 04:48

Согласимся в Process.waitall. Родитель будет ждать выхода дочерних ВСЕ.

Carlos Troncoso 13.11.2016 07:53

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

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 и ее ограничений.


Только что отредактировал, чтобы исправить явную ошибку (нет назначения задачи) и следовать совету @ (Джейсона Кинга).

Предположительно, это зеленые потоки, а не правильные потоки ОС?

John Topley 21.11.2008 22:21

Прочтите это о Ruby 1.9: igvita.com/2008/11/13/concurrency-is-a-myth-in-ruby

John Topley 22.11.2008 14:47

Должно быть: Thread.new(thing) { |it| doit(it) }, потому что thing сбрасывается на каждой итерации, поэтому нет гарантии, что правильный поток получит правильный thing.

smathy 18.09.2010 04:16

В версии 1.9 вы можете использовать команду Process.spawn. См. Также http://en.wikibooks.org/wiki/Ruby_Programming/Running_Multiple_Processes

Другие вопросы по теме