Настройка конвейера с использованием подпроцесса. Открыто: почему закрывать стандартный вывод, а не стандартный ввод? - PullRequest
0 голосов
/ 28 августа 2018

Документация Python 3 для subprocess.popen ( 1 ) представляет следующий пример кода для конвейеров:

from subprocess import Popen, PIPE
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]

Вызов p1.stdout.close () после запуска p2 важен для того, чтобы p1 мог получить SIGPIPE, если p2 выходит до p1.

Почему это необходимо? Предыдущие вопросы ( Замена конвейера оболочки , При каких условиях подпроцесс Python получает SIGPIPE? , Пример объяснения из модуля подпроцесса python ) имеют ответы о том, что p1.stdout имеет несколько считывателей, которые должны быть закрыты, чтобы предотвратить закрытие выходной трубы p1.


Какая связь между p2.stdin и p1.stdout, и нужно ли мне закрывать p2.stdin?

1 Ответ

0 голосов
/ 28 августа 2018

Нет, вам не нужно закрывать p2.stdin. На самом деле вы не можете, потому что это Ни один.

Это потому, что stdin=p1.stdout, тогда как объект потока Python создается только если stdin=subprocess.PIPE. См. подпроцесс Popen.stdin docs )


Я написал тестовую программу (Python 3), которая заканчивается на BrokenPipeError, если CLOSE_P1 = True, но вращается вечно ?? если CLOSE_P1 = False:

from subprocess import Popen, PIPE


CLOSE_P1 = True


p1 = Popen("ffmpeg "
           "-f rawvideo -pixel_format rgb24 -video_size 1x1 -i - "
           "-c copy -f rawvideo -".split(), stdin=PIPE, stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
assert p2.stdin is None

if CLOSE_P1:
    p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
p2.terminate()
while 1:
    p1.stdin.write(b'fsdafhdsf9jd9s8ha0')
...