Pythonでサブプロセスと対話する
標準入力に1行入れると、標準出力で1行返してくるようなプログラムがあって、起動のたびに7分かかってめんどうだから、プロセスを起動しっぱなしにしておいてHTTPサーバで包んでやろうと思ったんですよ。
サブプロセスの挙動としてはcatだと思っていい。それで
p = Popen(["cat"], stdin=PIPE, stdout=PIPE)
ってやってから
p.stdin.write("%s\n" % query) result = p.stdout.read()
ってやるとブロックされてしまった。ブロックを避けるために生のread/writeではなくp.communicateを使えとマニュアルには書いてあるが、それを使うと1回やり取りした時点でfdを閉じてしまうから2回目で「ValueError: I/O operation on closed file」になる。p.stdin.flush()は関係なし。p.stdout.read(1)ならブロックせずに読める。つまりはPythonのfile#read()がread(1024)みたいな挙動をして、しかも指定された量のデータがない場合にブロッキングすることが原因。POSIXのreadは
It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now...
という挙動をするので、POSIX環境でコードを書いているならos.readを使えばよい。
>>> p.stdin.write("hoge\n") >>> os.read(p.stdout.fileno(), 1024) 'hoge\n'
thanks id:moriyoshi, id:mopemope
追記: 1行単位で返ってくることが既知ならreadlineでもいいと言う指摘が多数ありました。