Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 一组Popen对象上的wait()_Python_Subprocess - Fatal编程技术网

Python 一组Popen对象上的wait()

Python 一组Popen对象上的wait(),python,subprocess,Python,Subprocess,我有许多Popen对象,每个对象代表我启动的一个长时间运行的命令。事实上,我不希望这些命令退出。如果其中任何一个退出,我想等待几秒钟,然后重新启动。有没有一个好的,蟒蛇式的方法来做到这一点 例如: import random from subprocess import Popen procs = list() for i in range(10): procs.append(Popen(["/bin/sleep", str(random.randrange(5,10))])) 天真

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

例如:

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)
,这样它就不会忙着等待,但我会失去精度


我觉得应该有一些很好的方法来等待一组PID——我说的对吗?

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

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!"
  • “重启崩溃的服务器”任务非常常见,除非有具体原因,否则可能不应该由自定义代码处理。请参见
    upstart
    systemd
    monit

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

  • 这里有一个使用良好的旧
    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)
    
    输出:
    它允许有效地响应过程完成和许多其他条件。

    奇怪的是,我没有找到一个优雅的解决方案。如果您想使用awesome
    gevent
    ,它有更丰富的工具选择,包括您可以随时添加到工作人员池的概念。对这与posix shell
    wait
    的行为相同。此行为的问题在于可能存在争用条件。如果进程在调用os.wait之前终止,它将不会被等待,并且您最终必须轮询每个进程。没有竞争条件!每个进程都由
    os返回一次。wait
    带有
    pid
    。如果在os.wait调用时没有子进程运行,则它没有任何可等待的内容。wait不会及时返回以确定生成了哪些进程。因此,如果进程在调用os.wait之前死亡,它将引发一个异常,表示没有可供等待的进程。再次出错!wait可以追溯到以前,因为有些进程从未被等待过。看我的例子。
        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']