Как запустить и забыть подпроцесс?
Вопрос
У меня давно запущенный процесс, и он нужен мне для запуска другого процесса (который тоже будет работать довольно долго).Мне нужно только начать это, а потом полностью забыть об этом.
Мне удалось сделать то, что мне было нужно, взяв немного кода из книги по программированию на Ruby, но я хотел бы найти наилучший / правильный способ и понять, что происходит.Вот что у меня получилось изначально:
exec("whatever --take-very-long") if fork.nil?
Process.detach($$)
Итак, так ли это, или как еще я должен это сделать?
После проверки приведенных ниже ответов я в итоге получил этот код, который, кажется, имеет больше смысла:
(pid = fork) ? Process.detach(pid) : exec("foo")
Я был бы признателен за некоторые объяснения о том, как fork
работает.[это я уже понял]
Отделялся $$
верно?Я не знаю, почему это работает, и мне бы очень хотелось лучше разобраться в ситуации.
Решение
Тот Самый 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
Цель отсоединения - просто сказать: "Мне все равно, когда ребенок завершит работу", чтобы избежать процессы зомбирования.
Отсоединение $$
это было неправильно.Из п.348 о Кирке (2-е изд.):
$$
Fixnum - номер процесса выполняемой программы.[r/o]
Этот раздел "Переменные и константы" в главе "Язык Ruby" очень удобен для декодирования различных сокращений ruby $
константы - однако онлайн-издание (первое
Итак, то, что вы на самом деле делали, это отсоединяли программу от самой себя, а не от ее дочернего элемента.Как уже говорили другие, правильный способ отсоединиться от дочернего элемента - это использовать pid дочернего элемента, возвращенный из fork()
.
Другие ответы хороши, если вы уверены, что хотите отсоединить дочерний процесс.Однако, если вы либо не возражаете, либо предпочли бы сохранить дочерний процесс подключенным (напримервы запускаете вспомогательные серверы / службы для веб-приложения), затем вы можете воспользоваться следующим сокращением
fork do
exec('whatever --option-flag')
end
Предоставление блока указывает 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