programma Python utilizzando os.pipe e os.fork) questione (
Domanda
Recentemente ho bisogno di scrivere uno script che esegue un os.fork () di dividere in due processi. Il processo bambino diventa un processo server e passa dati al processo genitore con un tubo creata con os.pipe () . Il bambino chiude l''r'
estremità del tubo e il genitore chiude l''w'
estremità del tubo, come al solito. Converte i rendimenti da pipe () in oggetti di file con os.fdopen .
Il problema che sto avendo è questo: Il processo con successo forchette, e il bambino diventa un server. Tutto funziona alla grande e il bambino scrive diligentemente i dati all'aperto read()
estremità del tubo. Purtroppo la fine genitore del tubo fa due cose strane:
A) Si blocca sull'operazione <=> sulla <=> estremità del tubo.
In secondo luogo, non riesce a leggere i dati che è stato messo sul tubo a meno che il <=> estremità è interamente chiuso.
Ho subito pensato che il buffering era il problema e ha aggiunto pipe.flush) (chiamate, ma questi non ha aiutato.
Qualcuno può far luce sul motivo per cui i dati non appare fino alla fine di scrittura sia completamente chiuso? E c'è una strategia per rendere il <=> non bloccante chiamata?
Questo è il mio primo programma Python che biforcuta o tubi utilizzati, quindi perdonatemi se ho fatto un semplice errore.
Soluzione
Stai usando read () senza specificare una dimensione, o trattare il tubo come un iteratore (for line in f
)? Se è così, questo è probabilmente la causa del problema - read () è definito a leggere fino alla fine del file prima di ritornare, piuttosto che leggere quello che è disponibile per la lettura. Ciò significa che bloccherà fino a quando il bambino chiama close ().
Nel codice di esempio legato a, questo è OK - il genitore si comporta in un modo di blocco, e usando solo il bambino a fini di isolamento. Se si desidera continuare, quindi utilizzare non-blocking IO come nel codice che avete inviato (ma essere pronti a trattare con i dati semi-completo), o leggere in blocchi (ad esempio r.read (dimensione) o r.readline () ) che blocca solo fino ad una determinata taglia / linea è stato letto. (Avrai ancora bisogno di chiamare a filo sul bambino)
Si presenta come trattare il tubo come un iteratore sta usando qualche ulteriore buffer come pure, per "for line in r:
" non può dare quello che vuoi se hai bisogno di ogni riga per essere immediatamente consumato. Potrebbe essere possibile disattivare questo, ma solo specificando 0 per la dimensione del buffer in fdopen non sembra sufficiente.
Ecco alcuni esempi di codice che dovrebbe funzionare:
import os, sys, time
r,w=os.pipe()
r,w=os.fdopen(r,'r',0), os.fdopen(w,'w',0)
pid = os.fork()
if pid: # Parent
w.close()
while 1:
data=r.readline()
if not data: break
print "parent read: " + data.strip()
else: # Child
r.close()
for i in range(10):
print >>w, "line %s" % i
w.flush()
time.sleep(1)
Altri suggerimenti
con
fcntl.fcntl(readPipe, fcntl.F_SETFL, os.O_NONBLOCK)
Prima di invocare il read () risolto entrambi i problemi. La chiamata read () non sta bloccando ei dati vengono visualizzati dopo appena un flush () sul lato di scrittura.
Vedo che hai risolto il problema del blocco di I / O e il buffering.
Una nota, se si decide di provare un approccio diverso: il sottoprocesso è l'equivalente / un sostituto per il linguaggio fork / exec. Sembra che questo non è quello che stai facendo: basta un bivio (non un exec) e lo scambio di dati tra i due processi - in questo caso la multiprocessing
modulo (in Python 2.6 +) sarebbe una misura migliore.
Il "padre" vs. parte "figlio" di forchetta in un'applicazione Python è sciocco. Si tratta di un lascito da 16 bit giorni unix. E 'un vezzo da un giorno in cui fork / exec e exec erano cose importanti per rendere la maggior parte di un piccolissimo processore.
Rompere il vostro codice Python in due parti distinte:. Genitore e figlio
La parte genitore dovrebbe usare sottoprocesso per eseguire la parte del bambino.
Una forcella e exec può accadere in qualche luogo in là - ma non c'è bisogno di preoccuparsi
.