2014-12-23 3 views
11

Я хотел, чтобы инициировать процесс моего питона сценария (main.py), в частности, я хочу, чтобы запустить следующую командузапустить полностью независимый процесс

`nohup python ./myfile.py &` 

и этот файл myfile.py должны даже после моих главных выходов питона скрипт.

Кроме того, я хочу получить pid нового процесса.

Я попытался os.spawnl*, os.exec* & subprocess.Popen методы, все прекращают мой myfile.py, если мой main.py сценарий завершается.

Возможно, у меня что-то не хватает.

Обновление: Могу ли я использовать os.startfile с xdg-open? Это правильный подход?

Пример

a = subprocess.Popen([sys.executable, "nohup /usr/bin/python25 /long_process.py &"],\ 
    stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) 
print a.pid 

Если я проверяю ps aux | grep long_process, я не мог видеть любой запущенный процесс.

long_process.py, который продолжает печатать текст: нет выхода.

Я делаю что-то не так здесь?

+0

Можете ли вы опубликовать минимальный пример, который не работает? После тривиального подпроцесса импорта python -c; subprocess.Popen (["sleep", "60"]) '' вывод 'ps' показывает, что' sleep' продолжает работать нормально после выхода Python. – user4815162342

+0

Вы используете Python с одним аргументом, «nohup/usr/bin/python25 ...» ', который не может работать, потому что исполняемый файл' python' будет искать скрипт в файле с именем «nohup/usr/bin»/... ', которого не существует. И поскольку вы указываете 'stderr' как' PIPE', даже не читая содержимое канала, вы никогда не увидите сообщение об ошибке. Потеряйте 'nohup' и' & 'и просто запустите' subprocess.Popen ([sys.executable, "/.../ long_process.py"]) '. Кроме того, не указывайте 'stdin' и' stderr' как трубы, если вы не имеете в виду это. – user4815162342

+0

'nohup' имеет смысл, когда вы начинаете процесс из оболочки. Я не вижу 'shell = True' в вашем вызове« Popen ». – 9000

ответ

10

Вы открываете свой долговременный процесс и держите трубку к ней. Поэтому вы ожидаете поговорить с ним. Когда вы запускаете скрипт запуска, вы больше не можете разговаривать с ним. Длительный процесс получает SIGPIPE и выходит.

Следующие только что сработали для меня (Linux, Python 2.7).

Создание давнего исполняемого файла:

$ echo "sleep 100" > ~/tmp/sleeper.sh 

Run Python REPL:

$ python 
>>> 

import subprocess 
import os 
p = subprocess.Popen(['/bin/sh', os.path.expanduser('~/tmp/sleeper.sh')]) 
# look ma, no pipes! 
print p.pid 
# prints 29893 

Выход из REPL и увидеть процесс все еще работает:

>>> ^D 
$ ps ax | grep sleeper 
29893 pts/0 S  0:00 /bin/sh .../tmp/sleeper.sh 
29917 pts/0 S+  0:00 grep --color=auto sleeper 

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

  • Ручка SIGPIPE в вашем долговременном процессе, не умирайте на нем. Живой без stdin после запуска процесса запуска.
  • Передайте все, что вам нужно, используя аргументы, среду или временный файл.
  • Если вы хотите двунаправленную связь, рассмотрите возможность использования именованного канала (man mkfifo) или сокета или записи соответствующего сервера.
  • Сделайте длинную вилку процесса после того, как будет выполнена начальная фаза двусторонней связи.
+0

Отличный ответ, это хороший момент, что процесс умирает из-за 'SIGPIPE'. (В коде из вопроса процесс никогда не начинался, но OP мог также попробовать другие варианты, которые начали и умерли из-за 'SIGPIPE'.) – user4815162342

+0

Он не создает« полностью независимый процесс »(что то, что« python пакет -demon'). Кроме того, [дочерний процесс не получит SIGPIPE в Python 2] (http://stackoverflow.com/a/22083141/4279). Хотя в простых случаях достаточно вашего решения (вы должны перенаправить на stdin/stdout/stderr для детей 'os.devnull', чтобы избежать ожидания ввода и/или ложного вывода на терминал). – jfs

+0

@ user4815162342: Он не умрет из-за SIGPIPE в Python 2 (у вопроса есть тег [tag: python2.7]). – jfs

5

Вы можете использовать os.fork().

import os 
pid=os.fork() 
if pid==0: # new process 
    os.system("nohup python ./myfile.py &") 
    exit() 
# parent process continues 
+0

Он работает +1, однако Popen очень удобен. – Garfield

3

Я не мог видеть любой запущенный процесс.

Вы не видите никакого процесса, так как дочерний процесс python немедленно завершает процесс. Недопустимые аргументы Popen: @user4815162342 says in the comment.

Чтобы запустить полностью независимый процесс, вы должны использовать python-daemon package:

#!/usr/bin/python25 
import daemon 
from long_process import main 

with daemon.DaemonContext(): 
    main() 

Хотя это может быть достаточно в вашем случае, чтобы начать ребенка с правильными Popen аргументами:

with open(os.devnull, 'r+b', 0) as DEVNULL: 
    p = Popen(['/usr/bin/python25', '/path/to/long_process.py'], 
       stdin=DEVNULL, stdout=DEVNULL, stderr=STDOUT, close_fds=True) 
time.sleep(1) # give it a second to launch 
if p.poll(): # the process already finished and it has nonzero exit code 
    sys.exit(p.returncode) 

Если дочерний процесс не требует python2.5, вместо этого вы можете использовать sys.executable (чтобы использовать ту же версию Python, что и родительский).

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