2010-07-07 18 views
11

Sto eseguendo alcuni sottoprocessi da Python in parallelo. Voglio aspettare fino a quando tutti i sottoprocessi hanno finito. Sto facendo una soluzione non elegante:Attendere la fine dei sottoprocessi con più processi paralleli

,

esiste una classe in grado di gestire più sottoprocessi? Il problema è che il metodo wait blocca il mio programma.

aggiornamento: Voglio mostrare i progressi durante il calcolo: qualcosa come "4/7 sottoprocesso finito ..."

Se siete curiosi root compilare il C++ script e eseguirlo.

risposta

4

Si potrebbe fare qualcosa di simile:

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() 

I processi verranno eseguiti in parallelo, e dovrai aspettare per tutti loro alla fine.

+4

sì, il problema è che non riesco a scrivere "#processo finito" durante le esecuzioni perché supponiamo che il primo sottoprocesso sia molto lento, p è uguale al primo 'ps' e python è in attesa e bloccato fino al primo finiture; python non può scrivere che tutti i sottoprocessi tranne il primo siano finiti. –

9

Se la tua piattaforma non è Windows, potresti probabilmente selezionare contro le pipe stdout dei tuoi sottoprocessi. La vostra applicazione sarà quindi bloccare fino a quando:

  • Uno dei descrittori di file registrati ha un evento di I/O (in questo caso, siamo interessati ad un hangup sul tubo di stdout del sottoprocesso)
  • I tempi sondaggio out

non a polpa-out esempio utilizzando epoll con Linux 2.6.xx:

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

Questo è pulito! C'è un modo per ottenere 'subproc.stdout' per stampare sul terminale mentre' mylongrunningproc' è in esecuzione? – unutbu

+0

La prima cosa che viene in mente è anche registrare le pipe stdout per gli eventi di input: 'poller.register (subproc.stdout, select.EPOLLHUP | select.EPOLLIN)'. Quindi puoi fare 'if flags & select.EPOLLIN: print done_proc.stdout.readline()'. Dovresti stare attento a bloccare indefinitamente nel caso in cui l'output non sia delimitato dalla linea. In linux I _think_ è possibile aggirare questo usando 'fcntl' per impostare il pipe stdout in modo da non bloccare e quindi catturare IOError con errno = EAGAIN. Ex - 'fcntl.fcntl (subproc.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)' –

+0

link di riferimento su letture non bloccanti della pipa - (http://www.gossamer-threads.com/lists/python/dev/658205) –

2

Come su

 
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) 
Problemi correlati