2012-04-28 17 views
7

Próbuję rozmawiać z proces potomny przy użyciu wywołania Python subprocess.Popen(). W moim prawdziwym kodzie implementuję typ IPC, więc chcę napisać trochę danych, przeczytać odpowiedź, napisać więcej danych, przeczytać odpowiedź i tak dalej. Z tego powodu nie mogę używać Popen.communicate(), która w przeciwnym razie działa dobrze dla prostego przypadku.Czytanie/pisanie do podprocesu Popen()

Ten kod pokazuje mój problem. Nigdy nie otrzymuje pierwszej odpowiedzi, wisi na pierwszym "wyniku czytania". Czemu? Jak mogę sprawić, aby działało to tak, jak oczekuję?

import subprocess 
p = subprocess.Popen(["sed", 's/a/x/g'], 
        stdout = subprocess.PIPE, 
        stdin = subprocess.PIPE) 

p.stdin.write("abc\n") 
print "Reading result:" 
print p.stdout.readline() 

p.stdin.write("cat\n") 
print "Reading result:" 
print p.stdout.readline() 

Odpowiedz

4

Spróbowałbym użyć Popen().communicate(), jeśli możesz, ponieważ robi wiele fajnych rzeczy dla ciebie, ale jeśli potrzebujesz użyć Popen() dokładnie tak, jak to opisałeś, musisz ustawić sed, aby opróżnić swój bufor po znakach nowej linii z opcja -l:

p = subprocess.Popen(['sed', '-l', 's/a/x/g'], 
        stdout=subprocess.PIPE, 
        stdin=subprocess.PIPE) 

i Twój kod powinien działać dobrze

+1

Rzeczywiście działa! Mój sed z jakiegoś powodu używa -u dla "niebuforowanego", nie -l, ale działa tak samo. To rozwiązuje mój przykładowy kod, ale niestety nie mój prawdziwy kod, ponieważ rzeczywiste polecenie nie jest sed, ale inny program python. Dobra odpowiedź, ale wskazałeś problem. –

+1

Tak, problem został rozwiązany. Problemem było buforowanie wyjścia wyniku. Wykonanie prostego stdout.flush() w moim podprocesie rozwiązało problem. Dzięki! –

3

sed jest wyjście jest buforowany i jedynie produkty jego danych, dopóki już dosyć skumulowana lub strumień wejściowy jest wyczerpana i zamknięte.

Spróbuj tego:

import subprocess 
p = subprocess.Popen(["sed", 's/a/x/g'], 
        stdout = subprocess.PIPE, 
        stdin = subprocess.PIPE) 

p.stdin.write("abc\n") 
p.stdin.write("cat\n") 
p.stdin.close() 

print "Reading result 1:" 
print p.stdout.readline() 

print "Reading result 2:" 
print p.stdout.readline() 

Należy pamiętać, że nie można tego zrobić wiarygodnie które ogromne dane jako wriring do stdin bloków gdy bufor jest pełny. Najlepszym sposobem jest użycie communicate().

+0

Ale sed nie działa w ten sposób, żeby uruchomić polecenie w powłoce bezpośrednio. Jeśli to zrobisz, odpowiedź przychodzi po każdym wierszu. Problem pozostaje, nawet jeśli po zapisaniu wywołasz p.stdin.flush(). W prawdziwym życiu napisałem również program, który nie jest buforowany i zachowuje się w ten sam sposób. Nie jestem przekonany, że problemem jest buforowanie. –

+2

Ach, miałeś rację, buforowanie było naprawdę problemem. –