【问题标题】:Python subprocess script keeps running after it is donePython子进程脚本完成后继续运行
【发布时间】:2013-12-08 01:28:33
【问题描述】:

在我的一个 Django 视图中,我正在调用一个 python 脚本并获取它的 pid:

from subprocess import Popen
p = Popen(['python', 'script.py'])
mypid = p.pid

当试图找出进程是否仍在从另一个页面运行时,我在mypid 上使用以下函数(感谢this question):

def doesProcessExist(pid):
    if pid < 0:
        return False
    try:
        os.kill(pid, 0)
    except OSError, e:
        return e.errno == errno.EPERM
    else:
        return True

无论我等待多长时间,进程仍然显示为正在运行。唯一阻止它的是,如果我使用 Popen 生成一个新的 python 脚本进程。 有没有办法解决这个问题?我不确定这是否是由于 Django 在脚本完成后没有正确关闭 python 或其他原因造成的。在 Ubuntu 的进程状态管理器中,进程显示为[python] &lt;defunct&gt;

--

我尝试过的所有script.py 都存在这个问题。我目前使用的简单如下:

from time import sleep
sleep(5)

【问题讨论】:

    标签: python django python-2.7 subprocess


    【解决方案1】:

    你看到的是一个僵尸进程。它不会继续运行。它不能。它已经死了。唯一剩下的就是一些允许相关进程检索其状态的信息。

    要确定子进程是否在没有阻塞的情况下处于活动状态,请调用p.poll()。如果它返回None,那么该进程仍然存在,否则你可以放心地忘记它(它已经被.poll() 收割了)。

    subprocess 模块调用_cleanup() 函数来获取Popen() constructor 中的僵尸进程。所以通常你的脚本不会创建很多僵尸进程。

    查看僵尸进程列表:

    import os
    #NOTE: don't use Popen() here
    print os.popen(r"ps aux | grep Z | grep -v grep").read(),
    

    【讨论】:

      【解决方案2】:

      真的,你做错了。当您使用像subprocess.Popen 这样的高级包装器时,您需要通过该对象管理进程。仅在其他地方拥有 PID 不足以管理它。

      如果您坚持使用 PID 而不是 Popen 对象,那么您应该使用 os 中的低级 API。

      幸运的是,您没有做任何复杂的事情,比如创建管道来与子进程对话。因此,您可以使用您最喜欢的spawn 变体启动它,然后使用waitpid 或其变体之一等待它。


      我假设您在单进程 Web 服务器中执行所有这些操作。如果您使用的是分叉 Web 服务器,而另一个页面可能在不同的进程中,即使使用 PID 也将不起作用。父进程必须收割子进程,而不是其他任意进程。如果你想让它发挥作用,你必须让事情变得更复杂,而且你真的必须先了解 Unix 进程模型,然后才能有人向你解释它。

      【讨论】:

        【解决方案3】:

        Unix 中的进程一直存在,直到父进程等待它们。在 thepopen 返回的对象上调用 wait 将等待该过程完成并等待它消失。在您这样做之前,它将以zombie process 的形式存在,请参阅this message,了解有关在您的网络服务器运行时让进程在后台消失的信息,而无需在前台线程/视图中等待它。

        所以,假设你这样做了

        p = subprocess.Popen(...)
        

        在某些时候你需要打电话 p.wait()

        【讨论】:

        • 您需要拨打的是wait,而不是close。此外,您需要在Popen 进程对象上调用它,而不是在您获得的任何管道上调用它(这很好,因为在这种情况下他没有拥有任何管道。)
        • @aba 谢谢;更新。将 C 的 pclose 与 subprocess.Popen 混淆了
        • 问题是我在另一个页面中等待进程,而不是它创建的页面,所以我没有子进程来运行 wait() 或communicate(),但只有 pid的子进程。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-09
        • 2014-12-17
        相关资源
        最近更新 更多