Как сразу читать стандартный вывод в подпроцессе Python - PullRequest
0 голосов
/ 10 июля 2020

Я пытаюсь создать два процесса python.

main.py

child = Popen(['python.exe', 'test.py'], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
stdout, stderr = child.communicate(input='hello world'.encode())
result = stdout.decode()
print(result)

test.py

value = sys.stdin.read()
sys.stdout.write(value)
time.sleep(10)

(time.sleep - это просто пример трудоемкой задачи.)

В этой ситуации main.py ждет 10 секунд, пока test.py завершится перед печатью.

Есть ли способ распечатать стандартный вывод из test.py сразу после sys.stdout.write?

1 Ответ

0 голосов
/ 10 июля 2020

Пример для вас, где вы читаете и пишете ребенку несколько раз (как вы указали в комментарии под вопросом).

Подпроцесс (test.py) будет:

  • прочитать строку
  • преобразовать каждую строку в верхний регистр и записать ее обратно,
  • спать 2 секунды
  • повторять до тех пор, пока не закончится ввод, а затем напишите окончательный строка

Основной процесс (main.py) будет:

  • три раза:
    • записать строку ввода в подпроцесс
    • прочтите ответ и скажите, сколько времени потребовалось, чтобы получить ответ
    • сон 5 секунд
  • в конце, прочтите любой окончательный результат, используя communicate, и сообщите об этом

Вот результат кода, который показан ниже:

writing to child: hello world 0
child replied with: HELLO WORLD 0
got answer back within 0.00022 seconds

writing to child: hello world 1
child replied with: HELLO WORLD 1
got answer back within 0.00012 seconds

writing to child: hello world 2
child replied with: HELLO WORLD 2
got answer back within 0.00021 seconds

final output from child: finishing

А вот код:

test.py

import sys
import time

while True:
    value = sys.stdin.readline()
    if not value:
        break
    sys.stdout.write(value.upper())
    sys.stdout.flush()
    time.sleep(2)

sys.stdout.write("finishing\n")

main.py

from subprocess import Popen, PIPE, STDOUT
import time

child = Popen(['python.exe', 'test.py'], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
time.sleep(1)

for i in range(3):
    data_in = f"hello world {i}"
    print(f"writing to child: {data_in}")

    time0 = time.time()
    child.stdin.write(f"{data_in}\n".encode())
    child.stdin.flush()
    data_out = child.stdout.readline()
    time1 = time.time()
    
    result = data_out.decode().strip()
    elapsed_time = time1 - time0
    print(f"child replied with: {result}")
    print(f"got answer back within {elapsed_time:.5f} seconds\n")
    time.sleep(5)

output, error = child.communicate()
print(f"final output from child: {output.decode()}")

(Проверено на Linux с использованием python вместо python.exe - надеюсь, он будет одинаково работать на Windows, хотя я могу Не тестирую.) * 105 1 *

Как видите, ответ получен, не дожидаясь завершения sleep.

(Очевидно, если время сна в родительском элементе уменьшится до менее 2 секунд, тогда ребенок не будет готов получить данные, когда они будут отправлены, так что тогда придется больше ждать, чтобы получить ответ.)

С таким двусторонним общением это очень просто оказаться в тупиковой ситуации (каждый процесс ждет, пока другой что-то сделает). Чтобы избежать этого, каждый процесс записывает ровно одну строку каждый раз, гарантируя, что она заканчивается новой строкой, и немедленно очищает выходной буфер - а процесс чтения использует readline() для чтения ровно одной строки (читается до новой строки). Тогда, надеюсь, они будут идти в ногу со временем и избежать взаимоблокировок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...