尽管进程已死,为什么仍会收到子进程资源警告?

Cha*_*ker 5 python subprocess kill kill-process

我一直在尝试找出如何启动不同的子流程实例,然后杀死它们然后创建新的实例。父python进程从不执行,只会杀死子进程。我在SO上跟踪了很多链接,但是一旦父python进程结束,我就会不断收到以下消息:

F/Users/Lucifer/miniconda3/envs/rltp/lib/python3.6/subprocess.py:761: ResourceWarning: subprocess 40909 is still running ResourceWarning, source=self)
Run Code Online (Sandbox Code Playgroud)

这似乎很有趣,因为我做到了,ps但是却一无所获:

  PID TTY           TIME CMD
 7070 ttys001    0:00.06 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp Lucifer
 7072 ttys001    0:00.61 -bash
17723 ttys002    0:00.06 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp Lucifer
17725 ttys002    0:00.06 -bash
38586 ttys002    0:00.16 sertop --no_init
Run Code Online (Sandbox Code Playgroud)

我只想开始一个过程:

self.serapi = subprocess.Popen(['sertop','--no_init'],
    stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,
    preexec_fn=os.setsid,shell=True
    ,)
Run Code Online (Sandbox Code Playgroud)

并杀死它:

    os.killpg(os.getpgid(self.serapi.pid), signal.SIGTERM)
Run Code Online (Sandbox Code Playgroud)

上面的代码本质上是从最上面的答案复制的:

如何终止以shell = True启动的python子进程

但我不确定为什么会收到此消息。我是否成功终止了子进程?我计划启动并杀死其中许多人。


注意我不知道或不需要shell=True。我只是复制了那个,就是我发布的答案/问题的答案。我宁愿没有那个参数。


根据我尝试的答案:

def kill(self):
    self.serapi.wait()
    #self.serapi.kill()
    self.serapi.terminate()
    #os.killpg(os.getpgid(self.serapi.pid), signal.SIGTERM)
    #self.serapi.wait()
Run Code Online (Sandbox Code Playgroud)

以及上述内容的不同排列方式,但似乎没有任何效果。有什么建议吗?

Dan*_*den 5

ResourceWarning: subprocess N is still running警告来自__del__该类的方法subprocess.Popen

如果您查看该方法的源代码,您将看到以下评论:

        # Not reading subprocess exit status creates a zombie process which
        # is only destroyed at the parent python process exit
        _warn("subprocess %s is still running" % self.pid,
              ResourceWarning, source=self)
Run Code Online (Sandbox Code Playgroud)

解决方案是确保您调用wait()子进程。

有关更多背景信息,请参阅手册页的“注释”部分。wait(2)

在 Python 中,处理这种情况的最简单方法是跟踪Popen您创建的所有对象,并确保有东西wait()直接或间接地调用它们。

或者,您可以安装一个SIGCHLD忽略SIGCHLD事件的处理程序;那么你的子进程将立即消失,但你现在将无法调用它们wait()。另请参阅如何防止僵尸子进程?以及如何处理 SIGCHLD?

  • 您应该先杀死该进程,然后等待它。在内核级别,“wait”的字面意思并不是“等待”,而是“接收事后信息”。该进程实际上可能不是僵尸进程,具体取决于您如何分叉它。但是“Popen”类“认为”子进程必须仍在运行(或者必须是僵尸进程),因为您还没有收到任何事后信息。那有意义吗? (2认同)