Почему стандартный вывод из подпроцесса (перенаправленный в небуферизованный файл) буферизуется?

Из http://docs.python.org/library/functions.html#open

Необязательный аргумент bufsize указывает желаемый размер буфера файла: 0 означает отсутствие буферизации, 1 означает буферизацию строки, любое другое положительное значение означает использование буфера (приблизительно) этого размера. Отрицательный размер буфера означает использование системного значения по умолчанию, которое обычно представляет собой строковую буферизацию для tty-устройств и полную буферизацию для других файлов. Если опущено, используется системное значение по умолчанию.

Я передаю 0 как bufsize ниже, но без использования flush(), вывод не записывается в файл, когда я запускаю main_process.
В чем причина?

# --------------------------------- sub_process.py
import sys
import time

if __name__ == '__main__':
    print 'printed from redirect.py'
    # why is the following flush() needed? 'std-output' is (?) unbuffered...
    sys.stdout.flush() 
    time.sleep(6)


# --------------------------------- main_process.py
import subprocess
import time

if __name__ == '__main__':
    p = subprocess.Popen(
        ['python', 'sub_process.py'],
        stdout=open('std-output', 'w', 0))
    time.sleep(3)
    p.terminate()

person Piotr Dobrogost    schedule 07.05.2011    source источник
comment
+1, я потратил около 30 минут, пытаясь понять, почему sys.stdout -> subprocess.PIPE не работал пару дней назад. flush() это ответ, но зачем он нам???   -  person This    schedule 07.05.2011


Ответы (2)


Расширение решения Magnus Skog (кстати, +1 :)):

В основном происходит то, что когда подпроцесс разветвляет новый процесс, он дублирует аргумент stdout в новый stdout подпроцесса (fileno = 1) с использованием os.dup2 (см. subprocess.Popen._execute_child), и это сохранит небуферизованное состояние (как это делает dup2), до сих пор все хорошо, но когда python быть запущен (в подпроцессе) по умолчанию, если python не видит флаг -u, он установит буфер stdout в линейный буфер (взгляните на основная функция Python.), которая переопределит установленный ранее флаг буферизации.

Надеюсь, это больше объясняет поведение, которое вы видели.

person Community    schedule 07.05.2011

Используйте python с флагом -u, например:

if __name__ == '__main__':
    p = subprocess.Popen(
        ['python', '-u', 'sub_process.py'],
        stdout=open('std-output', 'w'))
    time.sleep(3)
    p.terminate()
person ralphtheninja    schedule 07.05.2011
comment
Это работает, спасибо. Хотя, я все еще задаюсь вопросом, зачем это вообще нужно? - person Piotr Dobrogost; 07.05.2011
comment
Я предполагаю, что если вы пишете непосредственно в файл с помощью file.write(), это будет сделано без буферизации, но на самом деле вы пишете в него косвенно, поскольку python будет буферизовать ваши команды печати перед отправкой данных в ваш файл, поэтому вам нужно Флаг -u, чтобы указать Python не буферизовать команды печати. - person ralphtheninja; 07.05.2011
comment
sys.stdout.write('printed from redirect.py') дает тот же результат, что и print - в файл ничего не записывается - person Piotr Dobrogost; 07.05.2011