Почему stdin.readline не читает до конца - PullRequest
0 голосов
/ 05 мая 2019

Я новичок в 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 Ответ

2 голосов
/ 05 мая 2019

Ваш канал использует размер буфера по умолчанию для вашей системы (io.DEFAULT_BUFFER_SIZE). Считыватель заблокирован, потому что буфер еще не заполнен, поэтому в потоке нет индикатора, что чтение доступно.

Чтобы это исправить, вам нужно контролировать буферизацию. Есть два способа.

Во-первых, вы можете делать явный сброс после каждой записи.

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

Это эффективно реализует буферизацию строки, но в вашем собственном коде.

Во-вторых, вы можете выбрать режим буферизации в вызове Popen (), передавая bufsize kwarg. Положительные значения bufsize больше 1 устанавливают размер буфера этого значения, что означает, что ваш ридер будет получать сигналы готовности через определенные промежутки времени, когда этот буфер заполнен. Но есть и особые случаи:

  • 0 означает небуферизованный , так что каждая запись немедленно сбрасывается;
  • 1 означает строковый буфер , что является особым случаем, когда в пользовательском пространстве библиотека io сканирует записи на наличие новых строк и сбрасывает после них.

Вы можете передать bufsize=1 для принудительного сброса после перевода строки. В python3 это зависит от universal_newlines=True, но у вас это уже есть.

...