Может кто-нибудь объяснить тупик буфера трубы? - PullRequest
10 голосов
/ 04 марта 2010

Документация Python для Popen гласит:

Предупреждение. Используйте messages () вместо .stdin.write, .stdout.read или .stderr.read, чтобы избежать взаимных блокировок из-за того, что любой из других буферов буфера ОС заполняет и блокирует дочерний процесс.

Теперь я пытаюсь выяснить, как может возникнуть этот тупик и почему.

Моя ментальная модель: подпроцесс производит что-то для stdout / err, который буферизуется, и после заполнения буфера он сбрасывается в stdout / err подпроцесса, который отправляется через канал в родительский процесс.

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

В любом случае (с канальным буфером или нет) я не совсем уверен, как может возникнуть тупик. Единственное, о чем я могу думать, это о том, что к чему-то будут стремиться «глобальные» процессы конвейерного буфера ОС, что звучит странно. Другая причина заключается в том, что большее количество процессов будет использовать один канал, что не должно происходить само по себе.

Может кто-нибудь объяснить это?

Ответы [ 2 ]

6 голосов
/ 04 марта 2010

Осторожно, в этом есть тонкая ошибка.

Моя ментальная модель: производит подпроцесс что-то для stdout / err, что буферизуется и после заполнения буфера, он сбрасывается в стандартный вывод подпроцесс, который отправляется через канал к родительскому процессу.

Буфер совместно используется родительским и дочерним процессами.

Подпроцесс создает что-то для stdout, то есть тот же буфер, из которого предполагается, что родительский процесс читает.

Когда буфер заполнен, запись останавливается, пока буфер не будет очищен. Flush ничего не значит для канала, так как два процесса совместно используют один и тот же буфер.

Сброс на диск означает, что драйвер устройства должен сдвинуть байты вниз к устройству. Очистка сокета означает, что TCP / IP перестает ждать накопления буфера и отправки. Сброс к консоли означает прекращение ожидания новой строки и проталкивание байтов через драйвер устройства к устройству.

1 голос
/ 04 марта 2010

Возможна тупиковая ситуация, когда оба буфера (stdin и stdout) заполнены: ваша программа ожидает записи большего количества входных данных во внешнюю программу, а внешняя программа ожидает, чтобы вы сначала прочитали из ее выходного буфера.

Эту проблему можно решить с помощью неблокирующего ввода-вывода и правильной расстановки приоритетов в буферах. Вы можете попытаться заставить это работать самостоятельно, но communicate() просто делает это для вас.

...