python:杀死孩子或报告他们成功的简单方法?
Posted
技术标签:
【中文标题】python:杀死孩子或报告他们成功的简单方法?【英文标题】:python: simple approach to killing children or reporting their success? 【发布时间】:2011-03-24 21:02:42 【问题描述】:我想要
-
并行调用shell命令(例如下面的'sleep'),
报告他们的个人开始和完成情况并
能够使用“kill -9 parent_process_pid”杀死它们。
已经有很多关于这类事情的文章,但我觉得我还没有完全找到我正在寻找的优雅的 Pythonic 解决方案。对于完全不熟悉 python 的人,我还试图让内容相对可读(且简短)。
到目前为止,我的方法(参见下面的代码)是:
-
将 subprocess.call(unix_command) 放入报告命令开始和完成的包装函数中。
使用 multiprocess.Process 调用包装函数。
跟踪适当的 pid,将它们全局存储,然后在 signal_handler 中终止它们。
我试图避免定期轮询进程的解决方案,但我不确定为什么。
有更好的方法吗?
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)
【问题讨论】:
+1 以获得引人注目的标题。 我不知道 Python 可以杀死孩子...... @Zonda333:哦,当然。from __future__ import murder
.
【参考方案1】:
一旦subprocess.call
返回,子进程就完成了——call
的返回值就是子进程的returncode
。因此,在列表pids
中累积这些返回码(顺便说一句,在附加它的多进程和“主”进程之间不同步)并将它们发送9
信号“好像”它们是进程 ID 而不是返回代码,肯定是错的。
另一个绝对错误的问题是规范:
可以用 'kill -9 杀死他们 parent_process_pid'。
因为-9
意味着父进程不可能拦截信号(这是明确指定-9
的目的)——我想-9
因此在这里是虚假的。
您应该使用threading
而不是multiprocessing
(每个“保姆”线程或进程基本上什么都不做,只是等待它的子进程,那么为什么要在如此轻量级的任务上浪费进程呢?-);您还应该在主线程中调用suprocess.Process
(以启动子进程并能够获取其.pid
以放入列表中)并将生成的进程对象传递给等待它的保姆线程(和完成后报告并将其从列表中删除)。子进程 ID 列表应该由锁保护,因为主线程和几个保姆线程都可以访问它,并且集合可能比列表(更快的删除)更好,因为您不关心排序也不关心关于避免重复。
所以,大致(没有测试,所以可能存在错误;-)我会将您的代码更改为类似:
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)
【讨论】:
谢谢,这很有帮助。我会在清理完后回帖! @mathtick,不客气!我已经编辑了我的 A 以大致展示我如何看到代码结构最佳。 这 speculation.org/garrick/kill-9.html 对我来说是一个很好的教训。我想我是在第一次接触 linux 机器时养成了“-9”的习惯。 我在单独的答案中包含了上面代码的略微修改版本。 @Alex:为什么sigterm_handler
必须明确杀死所有守护线程,而sigint_handler
却没有?尽管有t.daemon=True
,但似乎确实需要明确的p.kill
。我也很困惑,即使 t.daemon=True
被注释掉,程序的行为(在 SIGTERM 或 SIGINT 之后)似乎也没有改变。 t.daemon=True
的目的是什么?【参考方案2】:
这段代码(下面的代码)似乎对我有用,从“top”或命令行中的 ctrl-c 杀死。亚历克斯建议的唯一真正变化是将 subprocess.Process 替换为 subprocess.Popen 调用(我不认为 subprocess.Process 存在)。
这里的代码也可以通过某种方式锁定标准输出来改进,这样就不会在进程之间打印重叠。
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)
【讨论】:
你是对的,没有 subprocess.Process -- 对不起,现在编辑我的 A 来修复它。以上是关于python:杀死孩子或报告他们成功的简单方法?的主要内容,如果未能解决你的问题,请参考以下文章