如何使用子进程停止由单个脚本生成的所有子进程

时间:2014-04-24 13:10:28

标签: python linux subprocess multiprocessing

我需要在我的软件包的一部分上运行unittest,对我来说最好的办法就是控制启动它然后杀死由multiprocessing模块生成的所有进程。

以下是我所说的:

test.py

import logging
import multiprocessing
import time
import random

log = logging.getLogger(__name__)

def start_consumers(conf, worker_count=5):
    manager = WorkerManager(conf, worker_count)
    manager.start()


class WorkerManager():
    def __init__(self, conf, worker_count=5):
        self.workers = []
        for num in range(worker_count):
            self.workers.append(WorkHandler(conf))

    def start(self):
        for worker in self.workers:
            worker.daemon = True
            worker.start()

        print 'started'
        for worker in self.workers:
            worker.join()

class WorkHandler(multiprocessing.Process):

    def __init__(self, conf, *args, **kwargs):
        super(WorkHandler, self).__init__(*args, **kwargs)
        self.conf = conf
        self.name = str(random.randint(0,100))

    def run(self):
        while True:
            print self.conf['foo'], self.name
            time.sleep(3)

if __name__ == "__main__":
    conf = {'foo': 'bar'}
    start_consumers(conf)

现在,如果我从linux终端运行此测试,我可以看到print语句,如果我这样做: ps aux | grep python我看到所有生成的子进程:

sergey    4081  0.0  0.1  71684 13164 pts/3    S+   08:58   0:00 python
sergey    4108  0.3  0.0  39092  6472 pts/3    S+   08:59   0:00 python test.py
sergey    4109  0.0  0.0  39092  4576 pts/3    S+   08:59   0:00 python test.py
sergey    4110  0.0  0.0  39092  4568 pts/3    S+   08:59   0:00 python test.py
sergey    4111  0.0  0.0  39092  4576 pts/3    S+   08:59   0:00 python test.py
sergey    4112  0.0  0.0  39092  4584 pts/3    S+   08:59   0:00 python test.py
sergey    4113  0.0  0.0  39092  4580 pts/3    S+   08:59   0:00 python test.py
sergey    4115  0.0  0.0  13588   944 pts/7    S+   08:59   0:00 grep --color=auto python

现在,如果我尝试使用test.py运行相同的subprocess,一切正常,直到我需要全部杀死它们:

>>> import subprocess as s
>>> p = s.Popen(['python', 'test.py'], stdout=s.PIPE)

问题:

当我在终端中按p时,为了实现类似的行为,使用此变量Ctrl+C执行某些操作的最优雅方法是什么?
换句话说,我希望得到类似于pkill -f "test.py"

的结果

UPDATE:

p.kill()p.terminate()无法满足我的需求:

这是我收集它们之后的结果:

sergey    4438  0.0  0.0      0     0 pts/3    Z+   09:16   0:00 [python] <defunct>
sergey    4439  0.0  0.0  39092  4572 pts/3    S+   09:16   0:00 python test.py
sergey    4440  0.0  0.0  39092  4568 pts/3    S+   09:16   0:00 python test.py
sergey    4441  0.0  0.0  39092  4576 pts/3    S+   09:16   0:00 python test.py
sergey    4442  0.0  0.0  39092  4580 pts/3    S+   09:16   0:00 python test.py
sergey    4443  0.0  0.0  39092  4580 pts/3    S+   09:16   0:00 python test.py

2 个答案:

答案 0 :(得分:2)

我相信您要找的是subprocess objectssubprocess.terminate()subprocess.kill()方法。

您可能必须将其与注册了atexit的方法相结合,该方法遍历您的子流程列表并终止它们。 EX:

def terminate_children(children):
    for process in children:
        process.terminate()

...
# Somewhere else in your code
children = [s.Popen(['python', 'test.py'], stdout=s.PIPE) for i in range(number_processes)] # Spools up number_processes child processes
atexit.register(terminate_children, children) # where children is a list of subprocesses

当您正常终止父进程时,这将正常终止所有子进程。

如果您试图从完全独立的脚本中删除流程而没有直接引用子代码,请参阅here。您基本上想要查看python os process management methods

答案 1 :(得分:1)

您可以尝试使用os.killpg()创建新会话并终止所有后代进程:

import os
import signal
from subprocess import Popen

p = Popen('python test.py', shell=True, preexec_fn=os.setsid)
# ... later
os.killpg(p.pid, signal.SIGTERM) # send signal to the process group

请参阅How to terminate a python subprocess launched with shell=True