Как запустить и забыть подпроцесс?

У меня длительный процесс, и мне нужно, чтобы он запустил другой процесс (который тоже долго будет работать). Мне нужно только запустить его, а потом полностью об этом забыть.

Мне удалось сделать то, что мне было нужно, выкопав некоторый код из книги по программированию на Ruby, но я хотел бы найти лучший / правильный путь и понять, что происходит. Вот что я получил изначально:

exec("whatever --take-very-long") if fork.nil?
Process.detach($$)


Итак, так ли это, или как еще мне это сделать?

После проверки ответов ниже я получил следующий код, который, кажется, имеет больше смысла:

(pid = fork) ? Process.detach(pid) : exec("foo")


Буду признателен за объяснение того, как fork работает. [получил это уже]

Отрывался $$ право? Я не знаю, почему это работает, и я бы очень хотел, чтобы лучше понять ситуацию.

5 ответов

Решение

fork Функция разделяет ваш процесс на две части.

Оба процесса затем получают результат функции. Ребенок получает значение ноль /nil (и, следовательно, знает, что это ребенок), и родитель получает PID ребенка.

Следовательно:

exec("something") if fork.nil?

заставит дочерний процесс запустить "что-то", а родительский процесс продолжит с того места, где он был.

Обратите внимание, что exec() заменяет текущий процесс на "что-то", поэтому дочерний процесс никогда не выполнит никакого последующего кода Ruby.

Призыв к Process.detach() похоже, это может быть неправильно. Я ожидал, что в нем будет PID ребенка, но если я правильно прочитал ваш код, это фактически отсоединяет родительский процесс.

Альнитак прав. Вот более явный способ написать это без $$

pid = Process.fork
if pid.nil? then
  # In child
  exec "whatever --take-very-long"
else
  # In parent
  Process.detach(pid)
end

Цель отсоединения - просто сказать: "Мне все равно, когда ребенок уходит", чтобы избежать зомби-процессов.

Другие ответы хороши, если вы уверены, что хотите отделить дочерний процесс. Однако, если вы либо не возражаете, либо предпочитаете оставить дочерний процесс присоединенным (например, вы запускаете субсерверы / службы для веб-приложения), то вы можете воспользоваться следующими сокращениями.

fork do
    exec('whatever --option-flag')
end

Предоставление блока указывает fork для выполнения этого блока (и только этого блока) в дочернем процессе, продолжая при этом в родительском процессе.

Отсоединение $$ был не прав. С р. 348 Кирка (2-е издание):

$$ Fixnum Номер процесса выполняемой программы. [Г / о]

Этот раздел "Переменные и константы" в главе "Язык Ruby" очень удобен для декодирования различных коротких рубинов. $ константы - однако онлайн-издание (первое

То, что вы на самом деле делали, это отрывало программу от самой себя, а не от ее дочернего элемента. Как уже говорили другие, правильный способ оторваться от ребенка - использовать пид ребенка, возвращенный из fork(),

Я нашел ответы выше сломал мой терминал и испортил вывод. это решение, которое я нашел.

   system("nohup ./test.sh &")

на случай, если у кого-то возникнет такая же проблема, моей целью было войти на ssh-сервер, а затем продолжать этот процесс в течение неопределенного времени. так что test.sh это

#!/usr/bin/expect -f
spawn ssh host -l admin -i cloudkey  
expect "pass"
send "superpass\r"
sleep 1000000
Другие вопросы по тегам