Как запустить и забыть подпроцесс?
У меня длительный процесс, и мне нужно, чтобы он запускал другой процесс (который тоже будет работать в тоже время). Мне нужно только запустить его, а затем полностью забыть об этом.
Мне удалось сделать то, что мне нужно, зачеркнув какой-то код из книги "Программирование рубинов", но я хотел бы найти лучший/правильный способ и понять, что происходит. Вот что я получил изначально:
exec("whatever --take-very-long") if fork.nil?
Process.detach($$)
Итак, так ли это или как мне это сделать?
После проверки ответов ниже я закончил с этим кодом, который, кажется, имеет больше смысла:
(pid = fork) ? Process.detach(pid) : exec("foo")
Буду признателен за то, как работает fork
. [получил это уже]
Правильно ли отсоединение $$
? Я не знаю, почему это работает, и мне очень хотелось бы лучше понять ситуацию.
Ответы
Ответ 1
Функция fork
разделяет ваш процесс на два.
Оба процесса затем получают результат функции. Ребенок получает значение zero/ nil
(и, следовательно, знает, что он является дочерним), а родитель получает PID дочернего элемента.
Следовательно:
exec("something") if fork.nil?
приведет к тому, что дочерний процесс начнет "что-то", и родительский процесс будет продолжен там, где он был.
Обратите внимание, что exec()
заменяет текущий процесс "чем-то", поэтому дочерний процесс никогда не будет выполнять какой-либо последующий код Ruby.
Вызов Process.detach()
выглядит как неправильный. Я бы ожидал, что у него будет дочерний PID, но если я правильно прочитаю ваш код, он фактически отменит родительский процесс.
Ответ 2
Альнитак прав. Здесь более явный способ написать его, без $$
pid = Process.fork
if pid.nil? then
# In child
exec "whatever --take-very-long"
else
# In parent
Process.detach(pid)
end
Цель отсоединения - просто сказать: "Мне все равно, когда ребенок заканчивается", чтобы избежать процессов зомби.
Ответ 3
Отсоединение $$
было неправильным. С. 348 Пикакса (2-е изд.):
$$
Fixnum Номер процесса выполняемой программы. [r/o]
Этот раздел "Переменные и константы" в главе "Язык Ruby" очень удобен для декодирования различных констант ruby short $
, однако онлайн-версия (первая
Итак, что вы на самом деле делали, это отделить программу от себя, а не от ее ребенка.
Как говорили другие, надлежащим способом отсоединиться от ребенка является использование дочернего pid, возвращенного из fork()
.
Ответ 4
Другие ответы хороши, если вы уверены, что хотите отделить дочерний процесс. Однако, если вы либо не возражаете, либо предпочтете, чтобы дочерний процесс был присоединен (например, вы запускаете под-серверы/службы для веб-приложения), вы можете воспользоваться следующей стенографией
fork do
exec('whatever --option-flag')
end
Предоставление блока сообщает fork выполнить этот блок (и только тот блок) в дочернем процессе, продолжая в родительском.
Ответ 5
Я нашел ответы выше сломал мой терминал и испортил выход. это решение, которое я нашел.
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