2013-05-27 11 views
43

Ho uno script chiamato 1st.py che crea un REPL (leggi-valuta-stampa-anello):Capire Popen.communicate

print "Something to print" 
while True: 
    r = raw_input() 
    if r == 'n': 
     print "exiting" 
     break 
    else: 
     print "continuing" 

ho poi lanciato 1st.py con il seguente codice:

p = subprocess.Popen(["python","1st.py"], stdin=PIPE, stdout=PIPE) 

e poi provato questo:

print p.communicate()[0] 

non è riuscito, fornendo questo traceback:

Traceback (most recent call last): 
    File "1st.py", line 3, in <module> 
    r = raw_input() 
EOFError: EOF when reading a line 

Puoi spiegare cosa sta succedendo qui per favore? Quando uso p.stdout.read(), si blocca per sempre.

risposta

35

.communicate() scrive input (non è presente alcun input in questo caso, quindi chiude semplicemente lo stdin del sottoprocesso per indicare al sottoprocesso che non c'è più input), legge tutto l'output e attende che il sottoprocesso esca.

L'eccezione EOFError viene sollevata nel processo figlio da raw_input() (dati previsti ma ottenuti EOF (nessun dato)).

p.stdout.read() si blocca per sempre perché cerca di leggere tutti uscita dal bambino allo stesso tempo, come il bambino attende di ingresso (raw_input()) che provoca una situazione di stallo.

Per evitare la situazione di stallo è necessario leggere/scrivere in modo asincrono (ad esempio, utilizzando fili o selezionate) o di sapere esattamente quando e quanto a lettura/scrittura, for example:

from subprocess import PIPE, Popen 

p = Popen(["python", "-u", "1st.py"], stdin=PIPE, stdout=PIPE, bufsize=1) 
print p.stdout.readline(), # read the first line 
for i in range(10): # repeat several times to show that it works 
    print >>p.stdin, i # write input 
    p.stdin.flush() # not necessary in this case 
    print p.stdout.readline(), # read output 

print p.communicate("n\n")[0], # signal the child to exit, 
           # read the rest of the output, 
           # wait for the child to exit 

Nota: si tratta un codice molto fragile se lettura/scrittura non sono sincronizzati; è deadlock.

Attenzione da block-buffering issue (qui è risolto utilizzando "-u" flag that turns off buffering for stdin, stdout in the child).

bufsize=1 makes the pipes line-buffered on the parent side.

+0

puoi dirmi qual è la differenza tra stampa >> p.stdin, i e p.stdin.write (i) –

+0

qui 'print' è' p.stdin.write (str (i) + "\ n"); p.stdin.flush() '. – jfs

+0

grazie ... Un'altra cosa per favore dimmi cosa sta facendo questo bufsize = 1? Anche "-u" in Popen (["python", "-u", "1st.py"], stdin = PIPE, stdout = PIPE, bufsize = 1) –

0

Il secondo bit di codice avvia il primo bit di codice come sottoprocesso con input e output con pipe. Quindi chiude il suo input e prova a leggere il suo output.

Il primo bit di codice tenta di leggere dallo standard input, ma il processo che lo ha avviato ha chiuso il suo input standard, quindi raggiunge immediatamente una fine del file, che in Python si trasforma in un'eccezione.

+0

grazie ... ma non voglio chiudere nessun input. Voglio stampare ovunque 1st.py sta stampando sul suo stdout. Successivamente, farò p.stdin.write ("Somthing to input") e poi p.communicate() [0] per stampare questo nel 2 ° codice. Potete aiutarmi? Semplicemente non voglio chiudere l'input o l'output. Sono novizio, quindi non esitate a correggermi. grazie –

16

Non utilizzare comunicare (input = ""). Scrive l'input per il processo, chiude lo stdin e quindi legge tutto l'output.

fare in questo modo:

p=subprocess.Popen(["python","1st.py"],stdin=PIPE,stdout=PIPE) 

# get output from process "Something to print" 
one_line_output = p.stdout.readline() 

# write 'a line\n' to the process 
p.stdin.write('a line\n') 

# get output from process "not time to break" 
one_line_output = p.stdout.readline() 

# write "n\n" to that process for if r=='n': 
p.stdin.write('n\n') 

# read the last output from the process "Exiting" 
one_line_output = p.stdout.readline() 

Cosa si dovrebbe fare per rimuovere l'errore:

all_the_process_will_tell_you = p.communicate('all you will ever say to this process\nn\n')[0] 

Ma dal momento che la comunicazione chiude il stdout e stdin e stderr, non è possibile leggere o scrivere dopo hai chiamato comunicare.

+0

grazie per la risposta ... ma è possibile vedere il mio primo programma è in attesa di input dell'utente e prima che stia stampando "Something to print". Quindi quello che voglio è: dal 2 ° processo voglio solo leggere quella linea ("Qualcosa da stampare"). e più tardi da questo (2 ° processo) voglio scrivere sul suo stdin e poi voglio di nuovo leggere qualsiasi cosa 1 ° processo (processo figlio) stia scrivendo sullo stdout. Allora, dimmi come posso farlo? –

+0

Ho commentato il codice. Ora dovrebbe fare quello che vuoi. È più chiaro? – User

+0

il processo genitore si blocca (si ferma per sempre) se utilizzo p.stdout.read()/readline() quando il processo figlio è in attesa di input dell'utente. –