Обновление в реальном времени вывода консоли исполняемого подпроцесса в Python - PullRequest
6 голосов
/ 05 апреля 2019

Я читал этот вопрос , , а этот и заметил, что предложенные там решения не помогли, что я пытаюсь осуществить.Идея похожа на этот вопрос , но я привожу лучший пример здесь.

Мне нужно создать графический интерфейс в Python 3.7 для мониторинга и управления выполнением устаревшего программного обеспечения, написанного наC. Сейчас я пытаюсь просто вызвать тестовый исполняемый файл из Python и напечатать его в графическом интерфейсе, но сейчас этого достаточно для печати на той же консоли, что и Python.Проблема в том, что исполняемый файл занимает очень много времени, чтобы полностью выполнить, но в то же время печатает консольные сообщения, мне нужно, чтобы эти сообщения были быстро прочитаны моим GUI.

Вот рабочий пример:

в Python 3.7:

import sys
from threading import Thread
import time
import subprocess

class HandleTarget(Thread):
    def __init__(self):
        Thread.__init__(self)

    def run(self):
        subprocess.Popen(["hello.exe"], stdout=sys.stdout, bufsize=1)

class Printer(Thread):
    def __init__(self):
        Thread.__init__(self)

    def run(self):
        for i in range(1, 15):
            sys.stdout.write("Hi back ("+str(i)+")!\n")
            time.sleep(1.0)

thread_1 = HandleTarget()
thread_2 = Printer()

# Launching threads:
thread_1.start()
thread_2.start()

Теперь исполняемый файл примера ("hello.exe") может быть собран в C следующим образом:

#include <stdio.h>
#include <time.h>

int main() {
    struct timespec time;
    double tic = 0;
    double toc = 0;

    for( int ii = 0; ii < 3 ; ii++){
        clock_gettime(CLOCK_MONOTONIC, &time);
        tic = time.tv_sec;
        toc = tic;

        while(toc-tic<3) {
        clock_gettime(CLOCK_MONOTONIC, &time);
        toc    = time.tv_sec;
        }
        printf("Hello #%d \n",ii);
    }
    return(0); 
}

В идеале мне нужны сообщения "Привет »и« Привет назад », которые будут чередоваться.Но если я запускаю приведенный выше скрипт на python, я получаю:

Hi back (1)!
Hi back (2)!
Hi back (3)!
Hi back (4)!
Hi back (5)!
Hi back (6)!
Hi back (7)!
Hi back (8)!
Hi back (9)!
Hello #0 
Hello #1 
Hello #2 
Hi back (10)!
Hi back (11)!
Hi back (12)!
Hi back (13)!
Hi back (14)!

По-видимому, вывод из исполняемого файла печатается только после завершения выполнения.Это означает, что если бы унаследованный исполняемый файл был запущен, то только после его завершения что-нибудь отобразилось бы.

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

1 Ответ

4 голосов
/ 10 апреля 2019

Подумайте о прочтении Popen.stdout:

https://docs.python.org/3/library/subprocess.html?highlight=subprocess#subprocess.Popen.stdout

Вот вывод обновленной программы:

$ python test.py
Hi back (1)!
Hi back (2)!
Hi back (3)!
Hello #0
Hi back (4)!
Hi back (5)!
Hi back (6)!
Hello #1
Hi back (7)!
Hi back (8)!
Hi back (9)!
Hello #2
Hi back (10)!
Hi back (11)!
Hi back (12)!
Hi back (13)!
Hi back (14)!

Обновленная программа:

import sys
from threading import Thread
import time
import subprocess

class HandleTarget(Thread):
    def __init__(self):
        Thread.__init__(self)

    def run(self):
        proc = subprocess.Popen(["hello.exe"], stdout=subprocess.PIPE)
        for line in proc.stdout:
            print(line.strip().decode('utf-8'))


class Printer(Thread):
    def __init__(self):
        Thread.__init__(self)

    def run(self):
        for i in range(1, 15):
            sys.stdout.write("Hi back ("+str(i)+")!\n")
            time.sleep(1.0)

thread_1 = HandleTarget()
thread_2 = Printer()

# Launching threads:
thread_1.start()
thread_2.start()

EDIT:

Я также изменил программу C для очистки стандартного вывода после печати, буферизованный стандартный вывод является основной причиной проблемы:

    printf("Hello #%d \n",ii);
    fflush(stdout);
...