Как запустить и забыть подпроцесс?
У меня длительный процесс, и мне нужно, чтобы он запустил другой процесс (который тоже долго будет работать). Мне нужно только запустить его, а потом полностью об этом забыть.
Мне удалось сделать то, что мне было нужно, выкопав некоторый код из книги по программированию на 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