为什么stdin.readline直到最后才读

时间:2019-05-05 19:51:51

标签: python python-3.x subprocess stdin

我是python的新手,我尝试将信息从其他python脚本发送到一个子进程,但是该子进程在主站停止发送之前不会读取任何内容。

我尝试发送新行以及以'\ n'结尾的行。 我知道我的子进程在流完成之前会被阻塞,但是如果我发送\ n或直接发送stdin.write('\ n'),它应该可以正确读取,但是不会读取

主要过程:

import subprocess
import time

child = subprocess.Popen("python3 example.py", shell=True, stdin=subprocess.PIPE, universal_newlines=True)
s = "this is the message"
print("MAIN:The child pid is: " + str(child.pid))
for i in range(0, 5):
    print("MAIN:iteration send:" + str(i))
    msg = s + "-" + str(i) + "\n"
    child.stdin.writelines(msg)
    time.sleep(1)
child.kill()

子流程:

import time
from sys import stdin

while True:
    try:
        print("CHILD:before read")
        s = stdin.readline()
        print("CHILD:after read")
        print("CHILD:message received is:" + s)
    except EOFError as err:
        print("M_READ_ERROR")
    time.sleep(1)

我的输出是这个

MAIN:The child pid is: 18041
MAIN:iteration send:0
CHILD:before read
MAIN:iteration send:1
MAIN:iteration send:2
MAIN:iteration send:3
MAIN:iteration send:4
CHILD:after read
CHILD:message received id:this is the message-0

但是我期望这样:

MAIN:The child pid is: 18041
MAIN:iteration send:0
CHILD:before read
CHILD:after read
CHILD:message received id:this is the message-0
MAIN:iteration send:1
CHILD:before read
CHILD:after read
CHILD:message received id:this is the message-1
MAIN:iteration send:2
CHILD:before read
CHILD:after read
CHILD:message received id:this is the message-2
MAIN:iteration send:3
CHILD:before read
CHILD:after read
CHILD:message received id:this is the message-3
MAIN:iteration send:4
CHILD:before read
CHILD:after read
CHILD:message received id:this is the message-4

1 个答案:

答案 0 :(得分:2)

您的管道正在使用系统的默认缓冲区大小(io.DEFAULT_BUFFER_SIZE)。读取器被阻塞,因为缓冲区尚未填充,因此流上没有指示可用读取的指示符。

要解决此问题,您需要控制缓冲。有两种方法。

首先,您可以在每次写入后进行显式刷新。

child.stdin.writelines(msg)
child.stdin.flush()

这有效地实现了行缓冲,但是使用您自己的代码。

第二,您可以通过传递bufsize kwarg在Popen()调用中选择缓冲模式。大于1的正bufsize设置该值的缓冲区大小,这意味着您的阅读器将在填充该缓冲区时隔一段时间获得就绪信号。但是也有一些特殊情况:

  • 0表示 unbuffered ,因此每个写操作立即刷新;
  • 1表示行缓冲,这是一种特殊情况,其中io库在用户空间中扫描写入的换行符并刷新换行符。

您可以通过bufsize=1强制在换行符之后刷新。在python3中,这取决于universal_newlines=True,但是您已经拥有了。