子进程.popen与主进程分离(Linux)

3
我试图打开一个子进程,但希望它与调用它的父脚本分离。现在,如果我调用subprocess.popen并且父脚本崩溃,子进程也会死亡。
我知道windows有几个选项,但我没有找到*nix的任何东西。
我也不需要使用subprocess来调用这个进程。我只需要能够调用另一个进程并获取pid即可。

1
可能相关:https://dev59.com/eW025IYBdhLWcg3w1JiG - NightShadeQueen
我看到了,但我不想分离和退出。我需要父脚本继续运行,但如果它崩溃,我不希望子进程也停止。 - korki696
1
不要在父进程中调用os._exit()...(在链接答案中的活动状态食谱中检查PID),请参阅http://code.activestate.com/recipes/278731-creating-a-daemon-the-python-way/。 - Joran Beasley
5个回答

3

使用Linux操作系统,这个问题不成问题。只需要使用Popen()函数即可。举个例子,下面是一个小小的dying_demon.py示例:

#!/usr/bin/python -u
from time import sleep
from subprocess import Popen
print Popen(["python", "-u", "child.py"]).pid
i = 0
while True:
    i += 1
    print "demon: %d" % i
    sleep(1)
    if i == 3:
        i = hurz # exception

分离出一个 child.py
#!/usr/bin/python -u
from time import sleep
i = 0
while True:
    i += 1
    print "child: %d" % i
    sleep(1)
    if i == 20:
        break

孩子继续数数(在控制台),而恶魔则因异常而死亡。

如果您的父Python进程崩溃,您可以使用此方法。但是,如果将此类代码合并到处理异常的更高级别的内容中,除非使用wait()或类似方法关闭它,否则将留下僵尸进程。 - Joshua Clayton

1

1
这个可能符合你的需求:
def cmd_detach(*command, **kwargs) -> subprocess.CompletedProcess:
    # https://dev59.com/HLvoa4cB1Zd3GeqP98TP
    # if using with ffmpeg remember to run it with `-nostdin`
    stdout = os.open(os.devnull, os.O_WRONLY)
    stderr = os.open(os.devnull, os.O_WRONLY)
    stdin = os.open(os.devnull, os.O_RDONLY)

    command = conform(command)
    if command[0] in ["fish", "bash"]:
        import shlex
        command = command[0:2] + [shlex.join(command[2:])]
    subprocess.Popen(command, stdin=stdin, stdout=stdout, stderr=stderr, close_fds=True, start_new_session=True, **kwargs)
    return subprocess.CompletedProcess(command, 0, "Detached command is async")

在Windows上,您可能需要

CREATE_NEW_PROCESS_GROUP = 0x00000200
DETACHED_PROCESS = 0x00000008
creationflags=DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP

替换为start_new_session=True


0

使用NOHUP选项fork子进程


我认为如果不使用shell=True,那么这个方法是行不通的,但如果没有必要的话,这会增加负担。 - Nick T

0

我使用python-daemon进行了以下操作,成功让它工作:

process = subprocess.Popen(["python", "-u", "Child.py"])
    time.sleep(2)
    process.kill()

然后在Child.py中:

with daemon.DaemonContext():
    print("Child Started")
    time.sleep(30)
    print "Done"
    exit()

我使用process.kill()来结束进程,否则会创建一个僵尸Python进程。现在我遇到的主要问题是,popen返回的PID与最终进程的PID不匹配。我可以通过在Child.py中添加一个函数来更新数据库中的PID来解决这个问题。

如果我漏掉了什么或者这种方法可行,请告诉我。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接