Запустите скрипт Python внутри Python, используя `subprocess.Popen` в режиме реального времени - PullRequest
0 голосов
/ 26 февраля 2019

Я хочу запустить скрипт Python (или любой исполняемый файл, для этого способа) из скрипта Python и получить вывод в режиме реального времени .Я следовал многим учебникам, и мой текущий код выглядит так:

import subprocess
with open("test2", "w") as f:
    f.write("""import time
print('start')
time.sleep(5)
print('done')""")

process = subprocess.Popen(['python3', "test2"], stdout=subprocess.PIPE)
while True:
        output = process.stdout.readline()
        if output == '' and process.poll() is not None:
            break
        if output:
            print(output.strip())
        rc = process.poll()

Первый бит просто создает файл, который будет запущен, для ясности.

У меня есть две проблемы с этим кодом:

  • Это не дает вывод в режиме реального времени.Он ждет до завершения процесса.

  • Он не прерывает цикл после завершения процесса.

Любая помощь будет приветствоваться.

РЕДАКТИРОВАТЬ: Спасибо @JohnAnderson за исправление первой проблемы: замена if output == '' and process.poll() is not None: на if output == b'' and process.poll() is not None:

1 Ответ

0 голосов
/ 27 февраля 2019

Прошлой ночью я намеревался сделать это, используя канал:

import os
import subprocess

with open("test2", "w") as f:
    f.write("""import time
print('start')
time.sleep(2)
print('done')""")

(readend, writeend) = os.pipe()

p = subprocess.Popen(['python3', '-u', 'test2'], stdout=writeend, bufsize=0)
still_open = True
output = ""
output_buf = os.read(readend, 1).decode()
while output_buf:
    print(output_buf, end="")
    output += output_buf
    if still_open and p.poll() is not None:
        os.close(writeend)
        still_open = False
    output_buf = os.read(readend, 1).decode()

Вынудить буферизовать изображение и прочитать один символ за раз (чтобы убедиться, что мы не блокируем записи изпроцесс заполнил буфер), закрывая конец записи по окончании процесса, чтобы убедиться, что чтение правильно перехватывает EOF.Посмотрев на subprocess, оказалось, что это было немного излишним.С PIPE вы получаете большую часть этого бесплатно, и я закончил с этим, который, кажется, работает нормально (вызывайте read столько раз, сколько необходимо, чтобы продолжить опустошение канала), просто с этим и предполагая, что процесс завершен, вам не нужно беспокоитьсяо его опросе и / или о том, что конец записи канала закрыт для корректного определения EOF и выхода из цикла:

p = subprocess.Popen(['python3', '-u', 'test2'],
                     stdout=subprocess.PIPE, bufsize=1,
                     universal_newlines=True)
output = ""
output_buf = p.stdout.readline()
while output_buf:
    print(output_buf, end="")
    output += output_buf
    output_buf = p.stdout.readline()

Это немного меньше в «реальном времени», так как в принципестрока буферизована.

Примечание. Я добавил -u к вашему вызову Python, поскольку вам также необходимо убедиться, что буферизация вызываемого процесса не мешает.

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