【问题标题】:Python spawn off a child subprocess, detach, and exitPython 生成子子进程、分离和退出
【发布时间】:2011-08-11 23:41:00
【问题描述】:

我想知道这是否是执行系统进程并与父进程分离的正确方法,尽管允许父进程退出而不创建僵尸和/或杀死子进程。我目前正在使用 subprocess 模块并执行此操作...

os.setsid() 
os.umask(0) 
p = subprocess.Popen(['nc', '-l', '8888'],
                     cwd=self.home,
                     stdout=subprocess.PIPE, 
                     stderr=subprocess.STDOUT)

os.setsid() 改变了进程组,我相信这是让进程在父进程退出时继续运行的原因,因为它不再属于同一个进程组。

这是正确的,也是一种可靠的执行方式吗?

基本上,我有一个远程控制实用程序,它通过套接字进行通信并允许远程启动进程,但我必须确保如果远程控制死机,它启动的进程继续运行不受影响。

我正在阅读有关双分叉的信息,但不确定这是否有必要和/或 subprocess.POpen close_fds 以某种方式解决了这个问题,只需要更改进程组?

谢谢。

伊利亚

【问题讨论】:

标签: python linux unix subprocess


【解决方案1】:

popen 在 Unix 上是 done using fork。这意味着您可以放心:

  1. 你在你的父进程中运行Popen
  2. 立即退出父进程

当父进程退出时,子进程被init 进程(OSX 上为launchd)继承,并且仍会在后台运行。

你的 python 程序的前两行不需要,这非常有效:

import subprocess
p = subprocess.Popen(['nc', '-l', '8888'],
                     cwd="/",
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT)

我正在阅读有关双叉的信息,但不确定是否有必要

如果您的父进程继续运行并且您需要保护您的孩子不与父进程一起死亡,则需要这样做。 This answer 展示了如何做到这一点。

双叉的工作原理:

  1. 通过os.fork()创建一个孩子
  2. 在这个子调用 Popen() 中,它启动了长时间运行的进程
  3. exit child:Popen 进程被init 继承并在后台运行

为什么父母必须立即退出?如果不立即退出会怎样?

如果您让父进程运行并且用户停止进程,例如通过ctrl-C (SIGINT) 或ctrl-\ (SIGQUIT) 然后它会杀死父进程和Popen 进程。

如果分叉后一秒退出怎么办?

然后,在这 1 秒期间,您的 Popen 进程容易受到 ctrl-c 等的攻击。如果您需要 100% 确定,请使用双分叉。

【讨论】:

  • 你能解释一下为什么父母必须立即退出吗?如果它不立即退出会发生什么?还有什么构成“立即”?如果它在分叉后一秒退出怎么办?
  • @Hubro:我已将您问题的答案添加到我上面的答案中,并澄清了一些解释不佳的事情
  • 如果子进程将大量输出放入管道,此进程将挂起。如果您不想与进程通信,请设置stdout=None。更多详情见:thraxil.org/users/anders/posts/2008/03/13/…
【解决方案2】:

对于 Python 3.8.x,这个过程有点不同。使用自 Python 3.2 起可用的 start_new_session 参数:

import shlex
import subprocess

cmd = "<full filepath plus arguments of child process>"
cmds = shlex.split(cmd)
p = subprocess.Popen(cmds, start_new_session=True)

这将允许父进程退出,而子进程继续运行。不确定僵尸。

start_new_session 参数在所有 POSIX 系统(即 Linux、MacOS 等)上均受支持。

在 macOS 10.15.5 上的 Python 3.8.1 上测试

【讨论】:

  • 我可以确认 start_new_session 在 Python 3.7 和 Python 3.2 中有效。在我看来,这是最干净的方法,至少对我来说是这样。
  • 我应该澄清它在 Debian 10 和 Python 3.7.3 中对我有用。
  • start_new_session=True 就像魅力一样。如果你想抑制输出,添加这些参数,stdout=subprocess.DEVNULLstderr=subprocess.STDOUT
  • python 3.8 以后最干净的方法是什么?
猜你喜欢
  • 1970-01-01
  • 2015-12-12
  • 2016-06-16
  • 2014-04-21
  • 1970-01-01
  • 2017-12-12
  • 2013-05-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多