Python process.stdout.readline()挂起。如何正确使用它?

Python process.stdout.readline()挂起。如何正确使用它?,python,subprocess,stdout,Python,Subprocess,Stdout,我想反复发送请求以处理标准输入,并从标准输出接收响应,而无需多次调用子流程。我可以使用p.communicate实现一次性请求-响应迭代,但是不要多次调用子流程,我需要使用:process.stdout.readline()。如何正确使用它? 我使用Python2.7 64位Windows 7。提前谢谢 main.py: import subprocess p = subprocess.Popen(['python','subproc.py'],stdin=subprocess.PIPE,std

我想反复发送请求以处理标准输入,并从标准输出接收响应,而无需多次调用
子流程。我可以使用
p.communicate
实现一次性请求-响应迭代,但是不要多次调用
子流程,我需要使用:
process.stdout.readline()。如何正确使用它?
我使用Python2.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
from __future__ import division
import pyximport
s=raw_input()
print 'Input=',s
while True:
    s = raw_input()
    print 'Input=',s
子脚本.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
from __future__ import division
import pyximport
s=raw_input()
print 'Input=',s
while True:
    s = raw_input()
    print 'Input=',s

您需要使用
通信
与您的子流程进行交互()。以下是主代码的更新版本:

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
文件将在那时关闭。

您可以进行一些小调整以使其正常工作。首先是使用
-u
选项禁用子级中的缓冲输出。第二种方法是将换行符与用户输入的消息一起发送到子进程,这样子进程中的
raw\u 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
您还应该将子进程包装在一个无限循环中,否则在发送第一条消息后,事情就会中断:

子脚本.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
from __future__ import division
import pyximport
s=raw_input()
print 'Input=',s
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

假设子进程将立即获得您发送到其stdin的完整数据是不安全的,因为缓冲区可能会妨碍它。如果必须保持文件打开以进行进一步输出,则至少应调用其
flush()
方法

此外,假设子进程的输出可以立即供您读取是不安全的。如果它不刷新(或关闭)其输出流,则可以缓冲EOL,如果您不提示子进程进一步操作,则您的
readline()
可能会永远等待。但是您的程序无法执行任何操作,因为它卡在了
readline()
中。如果子进程是为此构建的,那么您可能会让它工作,但在其他情况下,您需要使用更安全的方法,例如
subprocess.communicate()

正如您所观察到的,在同一子流程上多次调用
communicate()
是不起作用的。正如您从其文档中所期望的那样:它读取所有输出,直到文件结束,并等待子进程终止。要在此模式下发送多个输入,请构建一个包含所有输入的字符串,将其传递给
communicate()
,然后读取所有答案


或者,如果您确实需要在写入和读取之间进行切换,并且您的子流程没有专门为此而设计的工具,那么在单独的线程中进行读取和写入更安全,而不需要假设写入和读取完全交错。

使用
p.communicate()的问题
除了通过stdin发送数据外,它还会阻塞,直到子进程完成。OP希望能够在不重新启动子进程的情况下将数据重复发送到stdin。感谢您指出了flush这一点,当您只考虑与另一个程序通信时,这一点很容易被忽略,我调试了我的脚本的所有其他方面,试图找出我的错误所在。这是一个非常令人讨厌的bug来源,因为消息的一部分正确到达,而另一部分仍然挂在缓冲区中。