python 杀死子进程_python-如何使用子进程modu杀死(或避免)僵尸进程

python-如何使用子进程modu杀死(或避免)僵尸进程

当我使用子流程模块从另一个python脚本中启动一个python脚本时,当子流程“完成”时会创建一个僵尸进程。 除非杀死父python进程,否则无法杀死该子进程。

有没有办法杀死子进程而不杀死父进程? 我知道我可以通过使用wait()来做到这一点,但是我需要使用no_wait()运行脚本。

Dave asked 2020-01-27T06:25:09Z

8个解决方案

22 votes

不使用Popen()或communicate()将导致僵尸进程。

如果不需要命令的输出,则可以使用Popen():

>>> import subprocess

>>> subprocess.call(['grep', 'jdoe', '/etc/passwd'])

0

如果输出很重要,则应使用Popen()和communicate()获取stdout和stderr。

>>> from subprocess import Popen, PIPE

>>> process = Popen(['ls', '-l', '/tmp'], stdout=PIPE, stderr=PIPE)

>>> stdout, stderr = process.communicate()

>>> stderr

''

>>> print stdout

total 0

-rw-r--r-- 1 jdoe jdoe 0 2010-05-03 17:05 bar

-rw-r--r-- 1 jdoe jdoe 0 2010-05-03 17:05 baz

-rw-r--r-- 1 jdoe jdoe 0 2010-05-03 17:05 foo

David Narayan answered 2020-01-27T06:25:31Z

20 votes

僵尸进程不是真实的进程; 它只是进程表中的剩余条目,直到父进程请求子进程的返回码为止。 实际过程已经结束,除了上述过程表条目外,不需要其他资源。

我们可能需要有关您运行的流程的更多信息,以便实际提供更多帮助。

但是,如果您的Python程序知道子进程何时结束(例如,通过到达子stdout数据的末尾),则可以安全地调用.poll:

import subprocess

process= subprocess.Popen( ('ls', '-l', '/tmp'), stdout=subprocess.PIPE)

for line in process.stdout:

pass

subprocess.call( ('ps', '-l') )

process.wait()

print "after wait"

subprocess.call( ('ps', '-l') )

输出示例:

$ python so2760652.py

F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD

0 S 501 21328 21326 0 80 0 - 1574 wait pts/2 00:00:00 bash

0 S 501 21516 21328 0 80 0 - 1434 wait pts/2 00:00:00 python

0 Z 501 21517 21516 0 80 0 - 0 exit pts/2 00:00:00 ls

0 R 501 21518 21516 0 80 0 - 608 - pts/2 00:00:00 ps

after wait

F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD

0 S 501 21328 21326 0 80 0 - 1574 wait pts/2 00:00:00 bash

0 S 501 21516 21328 0 80 0 - 1467 wait pts/2 00:00:00 python

0 R 501 21519 21516 0 80 0 - 608 - pts/2 00:00:00 ps

否则,您可以将所有子项保留在一个列表中,然后再按.poll作为其返回代码。 每次迭代后,请记住从列表中删除返回码与None不同的子代(即完成的子代)。

tzot answered 2020-01-27T06:26:09Z

15 votes

如果删除子流程对象,使用del强制垃圾回收,将导致子流程对象被删除,然后已终止的进程将消失而不会终止您的解释器。 您可以先在python命令行界面中尝试一下。

user331905 answered 2020-01-27T06:26:30Z

6 votes

如果您仅使用.wait(),就可以了-做法如下:

import subprocess

def spawn_some_children():

subprocess.Popen(["sleep", "3"])

subprocess.Popen(["sleep", "3"])

subprocess.Popen(["sleep", "3"])

def do_some_stuff():

spawn_some_children()

# do some stuff

print "children went out to play, now I can do my job..."

# do more stuff

if __name__ == '__main__':

do_some_stuff()

您可以在Popen返回的对象上使用.wait()以检查其是否完成(无需等待)。 如果返回.poll(),则该子代仍在运行。

确保您不保留对Popen对象的引用-如果这样做,则不会对它们进行垃圾收集,因此您最终会遇到僵尸。 这是一个例子:

import subprocess

def spawn_some_children():

children = []

children.append(subprocess.Popen(["sleep", "3"]))

children.append(subprocess.Popen(["sleep", "3"]))

children.append(subprocess.Popen(["sleep", "3"]))

return children

def do_some_stuff():

children = spawn_some_children()

# do some stuff

print "children went out to play, now I can do my job..."

# do more stuff

# if children finish while we are in this function,

# they will become zombies - because we keep a reference to them

在上面的示例中,如果要摆脱僵尸,可以在每个孩子上使用.wait(),也可以使用.poll(),直到结果不是None。

两种方法都可以-要么不保留引用,要么使用.wait()或.poll()。

ibz answered 2020-01-27T06:27:08Z

5 votes

一旦其进程对象被垃圾回收,python运行时将负责摆脱僵尸进程。 如果看到僵尸环绕在它周围,则意味着您保留了一个过程对象,而没有将其称为等待,轮询或终止。

Peter answered 2020-01-27T06:27:29Z

1 votes

我不确定您的意思是“我需要使用no_wait()运行我的脚本”,但是我认为该示例可以满足您的需求。 进程不会长期成为僵尸。 当它们实际上已经终止时,父进程将仅在它们上为wait(),因此它们将迅速取消僵化。

#!/usr/bin/env python2.6

import subprocess

import sys

import time

children = []

#Step 1: Launch all the children asynchronously

for i in range(10):

#For testing, launch a subshell that will sleep various times

popen = subprocess.Popen(["/bin/sh", "-c", "sleep %s" % (i + 8)])

children.append(popen)

print "launched subprocess PID %s" % popen.pid

#reverse the list just to prove we wait on children in the order they finish,

#not necessarily the order they start

children.reverse()

#Step 2: loop until all children are terminated

while children:

#Step 3: poll all active children in order

children[:] = [child for child in children if child.poll() is None]

print "Still running: %s" % [popen.pid for popen in children]

time.sleep(1)

print "All children terminated"

最终的输出如下所示:

Still running: [29776, 29774, 29772]

Still running: [29776, 29774]

Still running: [29776]

Still running: []

All children terminated

Peter Lyons answered 2020-01-27T06:27:53Z

0 votes

我不确定no_wait()是什么意思。您是说不能阻止等待子进程完成吗? 假设如此,我认为这将满足您的要求:

os.wait3(os.WNOHANG)

Daniel Stutzbach answered 2020-01-27T06:28:13Z

0 votes

最近,由于我的python脚本,我遇到了这个僵尸问题。 实际的问题主要是由于杀死子进程而父进程不知道子进程已死。 所以我所做的就是,在子进程的kill信号之后添加popen.communicate(),以便父进程知道该子进程已死,然后内核更新了该子进程的pid,因为该子进程不再存在。 因此,现在没有形成僵尸。

PS:poll在这里也是一个选项,因为它检查子状态并将其传达给父状态。 通常,在子进程中,如果您不需要与stdout和stdin通信,则最好使用check_output或call。

Arunagiriswaran Ezhilan answered 2020-01-27T06:28:40Z

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值