对一组Popen对象进行wait()

时间:2014-06-02 20:17:04

标签: python subprocess

我有许多Popen对象,每个对象代表我已经开始的长时间运行的命令。实际上,我不希望这些命令退出。如果其中任何一个退出,我想等几秒钟然后重新启动。有没有一种好的,pythonic方式来做到这一点?

例如:

import random
from subprocess import Popen

procs = list()
for i in range(10):
    procs.append(Popen(["/bin/sleep", str(random.randrange(5,10))]))

一种天真的做法可能是:

for p in procs:
    p.wait()
    print "a process has exited"
    # restart code
print "all done!"

但这不会提醒我第一个退出的过程。所以我可以试试

for p in procs:
    p.poll()
    if p.returncode is not None:
        print "a process has exited"
        procs.remove(p)
        # restart code
print "all done!"

但是,这是一个紧凑的循环并将消耗CPU。我想我可以在循环中添加一个time.sleep(1),所以它没有忙碌等待,但我失去了精确度。

我觉得应该有一些很好的方式来等待一组pids - 我是对的吗?

3 个答案:

答案 0 :(得分:2)

  1. "重新启动崩溃的服务器"任务非常普遍,并且可能不应该由自定义代码处理,除非有具体原因。请参阅upstartsystemd以及monit

  2. multiprocessing.Pool对象听起来像是一场胜利 - 它会自动启动进程,甚至在需要时重新启动它们。不幸的是,它不是很容易配置。

  3. 这是一个老问号Popen的解决方案:

    import random, time
    from subprocess import Popen
    
    
    def work_diligently():
        cmd = ["/bin/sleep", str(random.randrange(2,4))]
        proc = Popen(cmd)
        print '\t{}\t{}'.format(proc.pid, cmd) # pylint: disable=E1101
        return proc
    
    
    def spawn(num):
        return [ work_diligently() for _ in xrange(num) ]
    
    
    NUM_PROCS = 3
    procs = spawn(NUM_PROCS)
    while True:
        print time.ctime(), 'scan'
        procs = [ 
            proc for proc in procs
            if proc.poll() is None
        ]
        num_exited = NUM_PROCS - len(procs)
        if num_exited:
            print 'Uhoh! Restarting {} procs'.format(num_exited)
            procs.extend( spawn(num_exited) )
        time.sleep(1)
    

    输出:

        2340    ['/bin/sleep', '2']
        2341    ['/bin/sleep', '2']
        2342    ['/bin/sleep', '3']
    Mon Jun  2 18:01:42 2014 scan
    Mon Jun  2 18:01:43 2014 scan
    Mon Jun  2 18:01:44 2014 scan
    Uhoh! Restarting 2 procs
        2343    ['/bin/sleep', '3']
        2344    ['/bin/sleep', '2']
    Mon Jun  2 18:01:45 2014 scan
    Uhoh! Restarting 1 procs
        2345    ['/bin/sleep', '2']
    Mon Jun  2 18:01:46 2014 scan
    Uhoh! Restarting 1 procs
        2346    ['/bin/sleep', '2']
    Mon Jun  2 18:01:47 2014 scan
    Uhoh! Restarting 2 procs
        2347    ['/bin/sleep', '3']
        2349    ['/bin/sleep', '2']
    

答案 1 :(得分:1)

如果您使用posix操作系统,则可以使用os.wait等待任何子进程。您可以获得process-id,您可以将其与列表的pid进行比较,以查找已终止的进程:

import random
from subprocess import Popen
import os

procs = {}
for i in range(10):
    proc = Popen(["/bin/sleep", str(random.randrange(5,10))])
    procs[proc.pid] = proc

while procs:
    pid, status = os.wait()
    proc = procs.pop(pid)
    print "process %d has exited" % proc.pid
    # restart code
print "all done!"

答案 2 :(得分:0)

twisted process API可以有效地响应流程的完成和许多其他条件。