Python 已经实现了communicate() 方法(它转到A.py,B.py 很好)。但是,它只适合简单的通信(您知道要预先发送什么数据),如果您需要更复杂的通信,例如:
send data to process B
read stdout
if stdout ...
do something bases on stdout
write to stdin
你必须实现你自己的communicate(),原来的实现here。
一步一步
我已经一步一步地测试和调试了,结果如下:
# For Popen(bufsize!=0)
A: process.stdin.write(b'hello\r\n')
B: line = sys.stdin.readline() # Hangs
所以在添加bufsize=0(无缓冲)之后
# Popen(bufsize=0)
A: process.stdin.write(b'hello\r\n') # Without \r\n B still hangs
B: line = sys.stdin.readline()
B: print('Send back', line.strip()) # Without strip it prints empty line
A: process.stdout.readline() # Hangs
那么什么有效?
# Popen(bufsize=0)
A: process.stdin.write(b'hello\r\n')
B: line = sys.stdin.readline()
B: print('Send back', line.strip())
B: sys.stdout.flush()
A: process.stdout.readline()
解释
您已将 缓冲 设置为 io.DEFAULT_BUFFER_SIZE(通常为 4090B)。来自docs:
bufsize 将在创建 stdin/stdout/stderr 管道文件对象时作为 io.open() 函数的相应参数提供:0 表示无缓冲(读取和写入是一个系统调用,并且可以返回短),1 表示行缓冲,任何其他正值表示使用大约该大小的缓冲区。负 bufsize(默认值)表示将使用系统默认值 io.DEFAULT_BUFFER_SIZE。
所以一开始A 不会刷新,因为它还没有填满缓冲区,因此B 正在等待。 Windows下是not possible to simply process.stdin.flush(),所以你必须使用bufsize=0。
另外写os.linesep (\r\n) 也很重要,因为readline()。
注意:我相信它应该也适用于 bufsize=1(行缓冲),但它没有。我不知道为什么。
同样的情况发生在B,它不会刷新sys.stdout,令我惊讶的是,B:sys.stdout 没有设置为无缓冲,因为:
bufsize 将在创建 stdin/stdout/stderr 管道文件对象时作为 io.open() 函数的相应参数提供
无论如何,您必须在B 中致电sys.stdout.flush()。
它适用于close(),因为它强制flush()。
给我代码
A.py:
import subprocess
import sys
process = subprocess.Popen([sys.executable, r'B.py'], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, bufsize=0)
for _ in range(3):
process.stdin.write(b'hello\r\n')
print(process.stdout.readline())
B.py:
import sys
for line in sys.stdin:
print('Send back', line.strip())
sys.stdout.flush()