REPL(read-eval-print-loop)を作成する1st.py
という名前のスクリプトがあります。
print "Something to print"
while True:
r = raw_input()
if r == 'n':
print "exiting"
break
else:
print "continuing"
次に、次のコードで1st.py
を起動しました。
p = subprocess.Popen(["python","1st.py"], stdin=PIPE, stdout=PIPE)
そして、これを試しました:
print p.communicate()[0]
次のトレースバックを提供して失敗しました:
Traceback (most recent call last):
File "1st.py", line 3, in <module>
r = raw_input()
EOFError: EOF when reading a line
ここで何が起こっているのか説明してください。 p.stdout.read()
を使用すると、永久にハングします。
.communicate()
は入力を書き込み(この場合は入力がないため、サブプロセスのstdinを閉じて、入力がないことをサブプロセスに示します)、すべての出力を読み取り、サブプロセスが終了するのを待ちます。
例外EOFErrorは、raw_input()
によって子プロセスで発生します(データを予期していましたが、EOF(データなし)を取得しました)。
p.stdout.read()
は、子がデッドロックを引き起こす入力(raw_input()
)を待つのと同時に、子からall出力を読み取ろうとするため、永久にハングします。 。
デッドロックを回避するには、非同期に読み取り/書き込みを行う必要があります(たとえば、スレッドまたはselectを使用して)、または読み取り/書き込みのタイミングと量を正確に知るには、 たとえば :
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
注:読み取り/書き込みが同期していない場合、非常に脆弱なコードです。デッドロックします。
block-buffering issue (ここでは、stdin、stdoutの子のバッファリングをオフにする "-u"フラグを使用することで解決します )。
通信(input = "")を使用しないでください。入力をプロセスに書き込み、その標準入力を閉じてから、すべての出力を読み取ります。
次のようにします:
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()
エラーを取り除くためにあなたがすること:
all_the_process_will_tell_you = p.communicate('all you will ever say to this process\nn\n')[0]
ただし、communicateはstdout
およびstdin
およびstderr
を閉じるため、communicateを呼び出した後は読み書きできません。
コードの2番目のビットは、パイプ処理された入力と出力を持つサブプロセスとしてコードの最初のビットを開始します。次に、入力を閉じて、出力の読み取りを試みます。
コードの最初のビットは標準入力からの読み取りを試みますが、それを開始したプロセスはその標準入力を閉じたため、すぐにファイルの終わりに到達し、Pythonは例外になります。