python:杀死孩子或报告他们成功的简单方法?

mat*_*ick 5 python subprocess parent-child multiprocessing

我想要

  1. 并行调用shell命令(例如下面的'sleep'),
  2. 报告他们的个人开始和完成情况
  3. 能够用'kill -9 parent_process_pid'杀死它们.

已经有很多关于这些事情的文章,但我觉得我还没有找到我正在寻找的优雅的pythonic解决方案.我也试图让对于完全不熟悉python的人保持相对可读(和简短).

到目前为止我的方法(见下面的代码)是:

  1. 将subprocess.call(unix_command)放在一个报告命令开始和完成的包装函数中.
  2. 使用multiprocess.Process调用包装器函数.
  3. 跟踪适当的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)
Run Code Online (Sandbox Code Playgroud)

Ale*_*lli 4

一旦subprocess.call返回,子流程就完成了——并且call的返回值是子流程的returncode。因此,在列表中累积这些返回代码pids(顺便说一句,附加它的多进程和“主”进程之间不同步)并向它们发送9信号“就好像”它们是进程 ID 而不是返回代码,这绝对是错误的。

这个问题的另一件事肯定是错误的,那就是规范:

能够用“kill -9parent_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)
Run Code Online (Sandbox Code Playgroud)