我需要在我的软件包的一部分上运行unittest
,对我来说最好的办法就是控制启动它然后杀死由multiprocessing
模块生成的所有进程。
以下是我所说的:
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"
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
答案 0 :(得分:2)
我相信您要找的是subprocess objects的subprocess.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。