python:杀死儿童或报告他们成功的简单方法?
我想python:杀死儿童或报告他们成功的简单方法?,python,subprocess,parent-child,multiprocessing,Python,Subprocess,Parent Child,Multiprocessing,我想 并行调用shell命令(例如下面的“sleep”) 报告各自的开始和完成情况,以及 能够用“kill-9父进程”杀死它们 已经有很多关于这类东西的文章,但我觉得我还没有找到我正在寻找的优雅的pythonic解决方案。对于完全不熟悉python的人来说,我还试图保持相对可读性(且简短) 到目前为止,我的方法(见下面的代码)是: 将subprocess.call(unix_命令)放入一个包装函数中,该函数报告命令的开始和完成 使用multiprocess.Process调用包装函数 跟踪适当的
import subprocess,multiprocessing,signal
import sys,os,time
def sigterm_handler(signal, frame):
print 'You killed me!'
for p in pids:
os.kill(p,9)
sys.exit(0)
def sigint_handler(signal, frame):
print 'You pressed Ctrl+C!'
sys.exit(0)
signal.signal(signal.SIGINT, sigint_handler)
signal.signal(signal.SIGTERM, sigterm_handler)
def f_wrapper(d):
print str(d) + " start"
p=subprocess.call(["sleep","100"])
pids.append(p.pid)
print str(d) + " done"
print "Starting to run things."
pids=[]
for i in range(5):
p=multiprocessing.Process(target=f_wrapper,args=(i,))
p.daemon=True
p.start()
print "Got things running ..."
while pids:
print "Still working ..."
time.sleep(1)
一旦返回,子进程就完成了,call
的返回值就是子进程的returncode
。因此,在列表pids
中累积这些返回码(顺便说一句,附加它的多进程和“主”进程之间不同步)并发送它们9
信号“好像”它们是进程ID而不是返回码,这绝对是错误的
问题的另一个明显错误是规格:
可以用'kill-9'杀死他们
父级\u进程\u pid'
由于-9
意味着父进程不可能截获信号(这是明确指定-9
的目的)——因此我认为-9
在这里是虚假的
您应该使用线程
而不是多处理
(每个“保姆”线程或进程基本上什么都不做,只是等待其子进程,那么为什么要在这样一个轻量级任务上浪费进程?-);您还应该在主线程中调用supprocess.Process
(以启动子进程,并能够获取其.pid
以放入列表),并将生成的进程对象传递给等待它的babysitter线程(完成后报告并将其从列表中删除)。子进程ID的列表应该由一个锁来保护,因为主线程和几个保姆线程都可以访问它,而且集合可能比列表(更快的删除)更好,因为您不关心排序,也不关心避免重复
所以,大致上(没有测试,所以可能有bug;-)我会将您的代码更改为s/之类的:
import subprocess, threading, signal
import sys, time
pobs = set()
pobslock = threading.Lock()
def numpobs():
with pobslock:
return len(pobs)
def sigterm_handler(signal, frame):
print 'You killed me!'
with pobslock:
for p in pobs: p.kill()
sys.exit(0)
def sigint_handler(signal, frame):
print 'You pressed Ctrl+C!'
sys.exit(0)
signal.signal(signal.SIGINT, sigint_handler)
signal.signal(signal.SIGTERM, sigterm_handler)
def f_wrapper(d, p):
print d, 'start', p.pid
rc = p.wait()
with pobslock:
pobs.remove(p)
print d, 'done, rc =', rc
print "Starting to run things."
for i in range(5):
p = subprocess.Popen(['sleep', '100'])
with pobslock:
pobs.add(p)
t = threading.Thread(target=f_wrapper, args=(i, p))
t.daemon=True
t.start()
print "Got things running ..."
while numpobs():
print "Still working ..."
time.sleep(1)
这段代码(下面的代码)似乎适合我,从“top”或命令行的ctrl-c进行杀戮。与Alex的建议相比,唯一真正的变化是将subprocess.Process替换为subprocess.Popen调用(我认为subprocess.Process不存在)
这里的代码也可以通过某种方式锁定stdout来改进,这样就不可能在进程之间打印重叠
import subprocess, threading, signal
import sys, time
pobs = set() # set to hold the active-process objects
pobslock = threading.Lock() # a Lock object to make sure only one at a time can modify pobs
def numpobs():
with pobslock:
return len(pobs)
# signal handlers
def sigterm_handler(signal, frame):
print 'You killed me! I will take care of the children.'
with pobslock:
for p in pobs: p.kill()
sys.exit(0)
def sigint_handler(signal, frame):
print 'You pressed Ctrl+C! The children will be dealt with automatically.'
sys.exit(0)
signal.signal(signal.SIGINT, sigint_handler)
signal.signal(signal.SIGTERM, sigterm_handler)
# a function to watch processes
def p_watch(d, p):
print d, 'start', p.pid
rc = p.wait()
with pobslock:
pobs.remove(p)
print d, 'done, rc =', rc
# the main code
print "Starting to run things ..."
for i in range(5):
p = subprocess.Popen(['sleep', '4'])
with pobslock:
pobs.add(p)
# create and start a "daemon" to watch and report the process p.
t = threading.Thread(target=p_watch, args=(i, p))
t.daemon=True
t.start()
print "Got things running ..."
while numpobs():
print "Still working ..."
time.sleep(1)
+我不知道巨蟒能杀死儿童…@Zonda333:哦,当然<代码>来自未来导入谋杀。谢谢,这很有帮助。我会在清理完后发回的@马蒂克,不客气!我编辑了我的A,以大致说明我将如何看到最好的代码结构。这对我来说是一个很好的教训。我想我是在第一次接触linux设备时养成了“-9”的习惯。我在一个单独的答案中包含了上面代码的一个稍加修改的版本。@Alex:为什么
sigterm\u handler
必须显式地杀死所有守护进程线程,而sigint\u handler
却没有?尽管t.daemon=True
,显式的p.kill
s似乎确实是需要的。我还感到困惑的是,即使注释掉了t.daemon=True
,程序的行为(在SIGTERM或SIGINT之后)似乎也没有改变。t.daemon=True
的目的是什么?您是对的,没有子进程.Process--很抱歉thinko;-,现在编辑我的A以修复它。