Небуферизованный вывод подпроцесса (последняя строка отсутствует) - PullRequest
3 голосов
/ 12 марта 2010

Я, должно быть, упускаю из виду нечто ужасно очевидное. Мне нужно выполнить программу на C, отобразить ее вывод в режиме реального времени и, наконец, проанализировать ее последнюю строку, что должно быть просто, поскольку последняя напечатанная строка всегда одинакова.

process = subprocess.Popen(args, shell = True,  
                           stdout = subprocess.PIPE, stderr = subprocess.PIPE)

# None indicates that the process hasn't terminated yet.
while process.poll() is None:

    # Always save the last non-emtpy line that was output by the child
    # process, as it will write an empty line when closing its stdout.
    out = process.stdout.readline()
    if out:
        last_non_empty_line = out

    if verbose:
        sys.stdout.write(out)   
        sys.stdout.flush()

# Parse 'out' here...

Время от времени, однако, последняя строка не печатается. Значение по умолчанию для bufsize Попенса равно 0, поэтому предполагается, что оно небуферизовано. Я также пытался, но безрезультатно, добавить fflush (stdout) к коду C непосредственно перед выходом, но кажется, что абсолютно нет необходимости очищать поток перед выходом из программы.

Идеи кому-нибудь?

Ответы [ 2 ]

3 голосов
/ 12 марта 2010

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

Вы должны будете продолжать читать process.stdout, пока не достигнете конца файла или пустой строки.

2 голосов
/ 12 марта 2010

readline() должен буферизовать текст в ожидании новой строки.

У вас всегда будет состояние гонки - никакие небуферизованные потоки не будут обрабатывать тот факт, что вы обрабатываете строку, затем проверяете выход, затем читаете строку, поэтому, если подпроцесс завершается, пока вы обрабатывая строку, вы больше ничего не прочитаете. Кроме того, оболочка, вероятно, вводит свою собственную буферизацию.

Так что вы можете либо:

  1. Используйте communicate() и оставьте подробный вывод во время работы подпроцесса.

  2. Обязательно продолжайте чтение после завершения процесса, пока не получите EOF.

Я бы также предложил изменить ваш код, чтобы вам не приходилось использовать shell=True.

...