如何 "adopt" python 中的子进程

How to "adopt" a child process in python

如何获取我没有为其创建对象的子进程的 pid?即

myProc = Popen(["sleep","30"])

对比

Popen(["sleep","30"])

我注意到如果我在发送终止信号后不对它们进行 poll() 或 wait() ,它们就会变成僵尸进程。在我的脚本中的某个点,我想找到我的脚本是父进程的所有子进程,并向它们发送信号或轮询它们。这在 python 中可能吗?有可能吗?

您可以使用 psutil 来查找父 Python 进程的子进程。例如:

import psutil
import os
import subprocess

subprocess.Popen(['sleep', '30'])

parent_pid = os.getpid()
parent = psutil.Process(parent_pid)

for child in parent.children():
    print(child)    # do something here

打印:

psutil.Process(pid=16822, name='sleep')

从那里你可以轮询他们,杀死他们等

通常,您不需要做任何事情 -- 当前的 subprocess 实现维护一个全局列表,其中包含活动的未引用 Popen 实例以及创建新的 Popen object ,这个列表是枚举的,每个进程都会调用 .poll()

因此,如果您没有对子流程的引用;它会自动等待您(如果您确实有参考,请自己致电 .wait())。

如果 child 进程是通过其他方式创建的,那么您可以调用 os.waitpid() 来收集 Unix 上死掉的子进程的退出状态:

while True:
    try:
        pid, status = os.waitpid(-1, os.WNOHANG) 
    except ChildProcessError:
        #  No more child processes exist
        break
    else:
        assert pid, "child process is still alive"

在 POSIX.1-2001 系统上,您可以调用 signal(SIGCHLD, SIG_IGN) 来自动获得 children。

如果你想在parent死亡时杀死所有children(发送信号);你可以 use prctl PR_SET_PDEATHSIG on Linux。如果 parent 因任何原因死亡,它会起作用,即,即使 parent 被 SIGKILL.

杀死,它也会起作用

psutil from 是一个可移植的解决方案:

#!/usr/bin/env python
import gc
import subprocess
import time

import psutil


for _ in range(10):
    subprocess.Popen(['sleep', '1'])  # no reference
time.sleep(2)  # wait until they are dead
gc.collect()  # run garbage collection, to populate _active list
subprocess.Popen(['sleep', '1'])  # trigger _cleanup()

for i in range(2):
    for child in psutil.Process().children():  # immediate children
        print(child, child.status())
    if i == 0:
        time.sleep(2)

输出

psutil.Process(pid=31253, name='sleep') sleeping
psutil.Process(pid=31253, name='sleep') zombie

注:

  1. psutil只显示了一个僵尸进程,其余的都在最后一次Popen()调用
  2. psutil 提供了针对 pid reuse 的保护,但它并不是在所有情况下都 100% 可靠——检查它是否足够适合你的情况(否则,使用上面的方法不依赖 child 的 pid)。