2010-07-07 13 views
11

Estoy ejecutando algunos subprocesos de python en paralelo. Quiero esperar hasta que cada subproceso haya terminado. Estoy haciendo una solución no elegante:Espere al final de los subprocesos con varios trabajos paralelos

runcodes = ["script1.C", "script2.C"] 
ps = [] 
for script in runcodes: 
    args = ["root", "-l", "-q", script] 
    p = subprocess.Popen(args) 
    ps.append(p) 
while True: 
    ps_status = [p.poll() for p in ps] 
    if all([x is not None for x in ps_status]): 
    break 

¿Hay una clase que pueda manejar múltiples subprocesos? El problema es que el método wait bloquea mi programa.

actualización: Quiero mostrar el progreso durante el cálculo: algo así como "4/7 subproceso terminó ..."

Si tienes curiosidad root compilar el C++ guión y ejecutarlo.

Respuesta

4

se podría hacer algo como esto:

runcodes = ["script1.C", "script2.C"] 

ps = [] 
for script in runcodes: 
    args = ["root", "-l", "-q", script] 
    p = subprocess.Popen(args) 
    ps.append(p) 

for p in ps: 
    p.wait() 

Los procesos se ejecutarán en paralelo, y usted esperar a que todos ellos al final.

+4

sí, el problema es que no puedo escribir '#process finished' durante las ejecuciones porque supongo que el primer subproceso es muy lento, p es igual al primer' ps' y python está esperando y congelado hasta la primera acabados; Python no puede escribir que todo el subproceso excepto el primero está terminado. –

9

Si su plataforma no es Windows, probablemente podría seleccionar contra las tuberías stdout de sus subprocesos. Su aplicación va a continuación, bloquear hasta que:

  • Uno de los descriptores de fichero registrado tiene un evento de E/S (en este caso, estamos interesados ​​en un cuelgue en el tubo de salida estándar del subproceso)
  • Los tiempos de la encuesta cabo

-no-concretarse a cabo ejemplo usando epoll con 2.6.XX Linux:

import subprocess 
import select 

poller = select.epoll() 
subprocs = {} #map stdout pipe's file descriptor to the Popen object 

#spawn some processes 
for i in xrange(5): 
    subproc = subprocess.Popen(["mylongrunningproc"], stdout=subprocess.PIPE) 
    subprocs[subproc.stdout.fileno()] = subproc 
    poller.register(subproc.stdout, select.EPOLLHUP) 

#loop that polls until completion 
while True: 
    for fd, flags in poller.poll(timeout=1): #never more than a second without a UI update 
     done_proc = subprocs[fd] 
     poller.unregister(fd) 
     print "this proc is done! blah blah blah" 
     ... #do whatever 
    #print a reassuring spinning progress widget 
    ... 
    #don't forget to break when all are done 
+0

¡Esto está limpio! ¿Hay alguna manera de hacer que 'subproc.stdout' imprima en el terminal mientras' mylongrunningproc' se está ejecutando? – unutbu

+0

Lo primero que se le viene a la mente es registrar también las tuberías stdout para eventos de entrada: 'poller.register (subproc.stdout, select.EPOLLHUP | select.EPOLLIN)'. Luego puede hacer 'if flags & select.EPOLLIN: print done_proc.stdout.readline()'. Debería tener cuidado con el bloqueo indefinido en caso de que la salida no sea eliminada en línea. En Linux, creo que puede evitar eso usando 'fcntl' para establecer que la tubería stdout no sea bloqueante y luego atrapar IOError con errno = EAGAIN. Ex - 'fcntl.fcntl (subproc.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)' –

+0

enlace de referencia en lecturas sin bloqueo de la tubería - (http://www.gossamer-threads.com/lists/python/dev/658205) –

2

¿Qué tal

 
import os, subprocess 
runcodes = ["script1.C", "script2.C"] 
ps = {} 
for script in runcodes: 
    args = ["root", "-l", "-q", script] 
    p = subprocess.Popen(args) 
    ps[p.pid] = p 
print "Waiting for %d processes..." % len(ps) 
while ps: 
    pid, status = os.wait() 
    if pid in ps: 
     del ps[pid] 
     print "Waiting for %d processes..." % len(ps) 
Cuestiones relacionadas