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

时间:2010-08-03 17:54:55

标签: python subprocess parent-child multiprocessing

我想

  1. 并行调用shell命令(例如下面的'sleep'),
  2. 报告他们的个人开始和完成情况以及
  3. 能够使用'kill -9 parent_process_pid'杀死它们。
  4. 已经有很多关于这些事情的文章,但我觉得我还没有找到我正在寻找的优雅的pythonic解决方案。我也试图让对于完全不熟悉python的人保持相对可读(和简短)。

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

    1. 将subprocess.call(unix_command)放在一个报告命令开始和完成的包装函数中。
    2. 使用multiprocess.Process调用包装函数。
    3. 跟踪相应的pid,全局存储它们,并在signal_handler中终止它们。
    4. 我试图避免定期轮询流程的解决方案,但我不确定原因。

      有更好的方法吗?

      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)
      

2 个答案:

答案 0 :(得分:4)

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

问题的另一个问题是绝对错误的是规范:

  

能够用'kill -9杀死它们   parent_process_pid”。

因为-9表示父进程无法拦截信号(即明确指定-9目的) - 我想{{1}因此在这里是虚假的。

你应该使用-9而不是threading(每个“保姆”线程,或者进程,除了等待它的子进程之外什么都没做,那么为什么要在这么轻量级的任务上浪费进程呢? - );你还应该在主线程中调用multiprocessing(以启动子进程并能够获取其suprocess.Process以放入列表中)并将生成的进程对象传递给等待的保姆线程为它(当它完成报告并从列表中删除它)。子进程ID的列表应该由一个锁保护,因为主线程和几个保姆线程都可以访问它,并且一个集合可能是比列表更好的选择(更快的删除),因为你不关心顺序也不关于避免重复。

所以,大致(没有测试,所以可能有bug ;-)我会将你的代码更改为s / like:

.pid

答案 1 :(得分:2)

这段代码(下面的代码)似乎对我起作用,从命令行中“top”或ctrl-c查杀。 Alex的建议唯一真正的改变是用subprocess.Popen调用替换subprocess.Process(我不认为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)