I'm new to python and i try to send information to one subprocess from other python script but the subprocess dont read anything until the main stop sending.
I try to send new lines and lines that ends on '\n'. I understand that my child process is being blocked until the stream finishes, but if I send \ n or directly stdin.write ('\ n'), it should read correctly, but it does not
Main process:
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()
Subprocess:
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)
And my output is this
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
But I expected something like:
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
Your pipe is using the default buffer size for your system (io.DEFAULT_BUFFER_SIZE
). The reader is blocked because the buffer has not yet filled, so there's no indicator on the stream that a read is available.
To fix this, you need to control buffering. There are two ways.
First, you could do an explicit flush after each write.
child.stdin.writelines(msg)
child.stdin.flush()
This effectively implements line buffering, but in your own code.
Second, you could select buffering mode in the Popen() call by passing the bufsize
kwarg. Positive bufsizes greater than 1 set a buffer size of that value, which means that your reader will get ready signals at intervals as that buffer is filled. But there are special cases too:
You can pass bufsize=1
to force flush after newlines. In python3, this depends on universal_newlines=True
, but you have this already.