启动完全独立的流程

时间:2014-12-23 17:03:44

标签: python python-2.7 subprocess fork child-process

我想从我的python脚本(main.py)启动一个进程,具体来说我想运行以下命令

`nohup python ./myfile.py &`

并且这个文件myfile.py应该在我的主要python脚本退出之后。

此外,我希望获得新进程的pid

我尝试了os.spawnl*os.exec*&如果我的main.py脚本退出,subprocess.Popen方法都会终止我的myfile.py

我可能会遗漏一些东西。

更新:我可以将os.startfilexdg-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 继续打印一些文字:没有退出。

我在这里做错了吗?

3 个答案:

答案 0 :(得分:13)

您打开长时间运行的流程并保持管道。所以你希望与它交谈。当yor启动程序脚本退出时,您无法再与它通信。 长时间运行的进程收到SIGPIPE并退出。

以下内容对我有用(Linux,Python 2.7)。

创建一个长期运行的可执行文件:

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

运行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,不要死在它上面。在启动程序进程退出后,没有标准输入。
  • 使用参数,环境或临时文件传递您想要的任何内容。
  • 如果您想要双向通信,请考虑使用命名管道(man mkfifo)或套接字,或者编写适当的服务器。
  • 在最初的双向沟通​​阶段完成后,使长时间运行的进程分叉。

答案 1 :(得分:7)

您可以使用os.fork()

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

答案 2 :(得分:6)

  

我看不到任何进程正在运行。

您没有看到任何进程正在运行,因为子python进程会立即退出。 Popen参数不正确为@user4815162342 says in the comment

要启动完全独立的流程,您可以使用python-daemon package或使用systemd / supervisord / etc:

#!/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,而不等待子进程完成(它对子级没有影响)。