我想编写一个执行外部脚本(B)的简单脚本(A)
所有这些都应该在不关闭流的情况下完成
A.py
import subprocess
process = subprocess.Popen(['python', 'B.py'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
for _ in range(3):
process.stdin.write(b'hello')
print(process.stdout.read())
B.py
import sys
for line in sys.stdin:
print(line)
输出应为:
>>> b'hello'
>>> b'hello'
>>> b'hello'
问题是A只是等待
print(process.stdout.read())
如果我通过添加close():
来修改A.for _ in range(3):
process.stdin.write(b'hello')
process.stdin.close()
print(process.stdout.read())
我明白了:
>>> b'hello\n'
>>> Traceback (most recent call last):
>>> File "A.py", line 7, in <module>
>>> process.stdin.write(b'hello')
>>> ValueError: write to closed file
答案 0 :(得分:3)
communicate()
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:
在创建stdin / stdout / stderr管道文件对象时,bufsize 将作为io.open()函数的相应参数提供:0表示无缓冲(读取和写入是一个系统调用,可以返回short),1表示行缓冲,任何其他正值表示使用大约该大小的缓冲区。负bufsize(默认值)表示将使用系统默认值io.DEFAULT_BUFFER_SIZE。
因此,首先A
将不会刷新,因为它尚未填充其缓冲区,因此B
正在等待。在Windows下是not possible to simply process.stdin.flush()
,因此您必须使用bufsize=0
。
由于readline()
,写os.linesep
(\r\n
)也很重要。
注意: 我相信它应该也适用于bufsize=1
(行缓冲),但事实并非如此。我不明白为什么。
然后,当B
无法刷新sys.stdout
时,同样的情况也会发生,令我感到惊讶的是,B:sys.stdout
未设置为无缓冲,因为:< / p>
在创建stdin / stdout / stderr管道文件对象时,bufsize 将作为io.open()函数的相应参数提供
无论如何,您必须在sys.stdout.flush()
中致电B
。
它与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()