process.stdout.readline() 挂起了。如何正确使用?
我想要反复发送请求来处理标准输入,并从标准输出接收响应,而不是多次调用 subprocess
。我可以通过 p.communicate
实现一次请求-响应的循环,但如果不想多次调用 subprocess
,我需要使用 process.stdout.readline()
,但这会导致程序挂起。请问该如何正确使用它?我使用的是 Python 2.7 64位,Windows 7。提前谢谢!
main.py
:
import subprocess
p = subprocess.Popen(['python','subproc.py'],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
while True:
s=raw_input('Enter message:')
p.stdin.write(s)
p.stdin.flush()
response = p.stdout.readline()
if response!= '':
print "Process response:", response
else:
break
subproc.py
:
from __future__ import division
import pyximport
s=raw_input()
print 'Input=',s
3 个回答
你需要使用 communicate
来和你的子进程进行互动(可以查看这个链接了解更多:https://docs.python.org/2/library/subprocess.html#subprocess.Popen.communicate)。下面是你主代码的一个更新版本:
import subprocess
p = subprocess.Popen(['python','subproc.py'],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
while True:
s = raw_input('Enter message:')
response, _ = p.communicate(s)
if response!= '':
print "Process response:", response
else:
break
另外,你要注意的是,虽然你的主代码里有一个循环,但子进程的代码只会运行一次。只有第一次循环能正确接收到响应,第二次调用 communicate
时会出现错误,因为到那时子进程的 stdin
文件已经关闭了。
不能指望子进程会立刻收到你发送到它标准输入(stdin)的所有数据,因为在这个过程中可能会有缓冲区的干扰。如果你需要保持文件打开以便继续输出,至少应该调用它的 flush()
方法来确保数据被发送出去。
另外,也不能指望子进程的输出会马上可以读取。如果它没有刷新(flush)或关闭它的输出流,那么输出的结束符(EOL)可能会被缓冲,这样你如果不采取措施让子进程继续工作,你的 readline()
可能会一直等待下去。这时候你的程序就无法继续,因为它被卡在 readline()
里。如果子进程是为这种情况设计的,可能会正常工作,但如果不是,你就需要使用更安全的方法,比如 subprocess.communicate()
。
正如你所观察到的,不能对同一个子进程多次调用 communicate()
。这是符合它文档中说明的:它会读取所有输出直到文件结束,并等待子进程结束。如果你想在这种模式下发送多个输入,应该把所有输入拼成一个字符串,传给 communicate()
,然后再读取所有的回答。
另外,如果你确实需要在写入和读取之间交替进行,而你的子进程又没有特别设计来处理这种情况,那么更安全的做法是将读取和写入放在不同的线程中,且不指望写入和读取能够完美交错。
要让这个程序正常工作,你可以做几个小调整。首先,在子进程中使用 -u
选项来关闭缓冲输出。其次,要在用户输入的消息后面加上一个换行符,这样子进程中的 raw_input
调用才能完成。
main.py
import subprocess
# We use the -u option to tell Python to use unbuffered output
p = subprocess.Popen(['python','-u', 'subproc.py'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
while True:
s = raw_input('Enter message:')
p.stdin.write(s + "\n") # Include '\n'
p.stdin.flush()
response = p.stdout.readline()
if response != '':
print "Process response:", response
else:
break
你还应该把子进程放在一个无限循环里,不然在发送第一条消息后,程序就会出问题:
subproc.py
:
while True:
s = raw_input()
print 'Input=',s
输出:
dan@dantop:~$ ./main.py
Enter message:asdf
Process response: Input= asdf
Enter message:asdf
Process response: Input= asdf
Enter message:blah blah
Process response: Input= blah blah
Enter message:ok
Process response: Input= ok