【问题标题】:How to stop all child processes spawnedby a single script using subprocess如何使用子进程停止由单个脚本生成的所有子进程
【发布时间】:2014-04-24 13:10:28
【问题描述】:

我需要在我的包的一部分上运行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 终端运行这个测试,我可以看到打印语句,如果我这样做的话: 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

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

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

问题:

当我在终端中按下Ctrl+C 时,使用这个变量p 来实现类似行为的最优雅的方法是什么?
换句话说,我想获得类似于pkill -f "test.py"的结果

更新:

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

【问题讨论】:

    标签: python linux subprocess multiprocessing


    【解决方案1】:

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

    您可能必须将其与在atexit 注册的方法结合起来,该方法遍历您的子进程列表并终止它们。例如:

    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

    【讨论】:

    • 不安静,我知道它需要去哪里吗?目标是不更改源代码并创建某种清理过程,但能够从单独的代码中终止它们。
    • 我假设你在正确的地方把你的子进程卷起来? atexit 代码将出现在任何发生的地方。只需存储您正在创建的 p 对象的列表,然后在我的示例中将它们作为 children 参数传递。我将对其进行编辑以使其更清晰。
    • 不,这不是我想要的,您的代码将生成 N 进程数,每个进程将跨越 N 子进程数
    • 看我最后贴的链接。如果这些都不是你想要的,你需要让你的问题更清楚。
    • 我成功地使用你的方法清理了太多导致 CPU 过载并挂起 MAC OS 的通信子进程。
    【解决方案2】:

    您可以尝试使用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

    【讨论】:

      猜你喜欢
      • 2019-07-12
      • 2010-11-01
      • 2018-08-02
      • 2013-09-26
      • 2013-09-10
      • 2011-01-21
      • 2016-02-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多