Отключить буферизацию вывода - PullRequest
456 голосов
/ 20 сентября 2008

Включена ли буферизация вывода по умолчанию в интерпретаторе Python для sys.stdout?

Если ответ положительный, как можно его отключить?

Предложения на данный момент:

  1. Используйте ключ командной строки -u
  2. Обернуть sys.stdout в объект, который мигает после каждой записи
  3. Set PYTHONUNBUFFERED env var
  4. sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

Есть ли другой способ программно установить глобальный флаг в sys / sys.stdout во время выполнения?

Ответы [ 16 ]

3 голосов
/ 11 июня 2013

(Я оставил комментарий, но он как-то потерялся. Итак, еще раз:)

  1. Как я заметил, CPython (по крайней мере, в Linux) ведет себя по-разному в зависимости от того, куда выводятся данные. Если он переходит в tty, то вывод сбрасывается после каждого '\n'
    Если речь идет о канале / процессе, то он буферизуется, и вы можете использовать решения на основе flush() или вариант -u , рекомендованный выше.

  2. Немного связано с буферизацией вывода:
    Если вы перебираете строки во вводе с

    for line in sys.stdin:
    ...

затем реализация для в CPython будет некоторое время собирать входные данные и затем выполнять тело цикла для набора строк ввода. Если ваш сценарий собирается записать вывод для каждой строки ввода, это может выглядеть как буферизация вывода, но на самом деле это пакетная обработка, и поэтому ни один из методов flush() и т. Д. Не поможет. Интересно, что у вас нет такого поведения в pypy . Чтобы избежать этого, вы можете использовать

while True: line=sys.stdin.readline()
...

3 голосов
/ 30 июня 2012

Вариант, который работает без сбоев (по крайней мере, на win32; python 2.7, ipython 0.12), затем вызывается впоследствии (несколько раз):

def DisOutBuffering():
    if sys.stdout.name == '<stdout>':
        sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

    if sys.stderr.name == '<stderr>':
        sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 0)
3 голосов
/ 15 ноября 2009

Вы также можете использовать fcntl для изменения файловых флагов на лету.

fl = fcntl.fcntl(fd.fileno(), fcntl.F_GETFL)
fl |= os.O_SYNC # or os.O_DSYNC (if you don't care the file timestamp updates)
fcntl.fcntl(fd.fileno(), fcntl.F_SETFL, fl)
2 голосов
/ 20 сентября 2008

Вы можете создать небуферизованный файл и назначить этот файл для sys.stdout.

import sys 
myFile= open( "a.log", "w", 0 ) 
sys.stdout= myFile

Вы не можете волшебным образом изменить поставляемый системой стандартный вывод; так как он поставляется вашей программой на Python операционной системой.

1 голос
/ 26 ноября 2018

В Python 3 вы можете «обезьянько-патчить» функцию печати, чтобы всегда отправлять flush = True:

_orig_print = print

def print(*args, **kwargs):
    _orig_print(*args, flush=True, **kwargs)
1 голос
/ 20 сентября 2008

Один из способов получить небуферизованный вывод - использовать sys.stderr вместо sys.stdout или просто вызвать sys.stdout.flush(), чтобы явно вызвать запись.

Вы можете легко перенаправить все напечатанное, выполнив:

import sys; sys.stdout = sys.stderr
print "Hello World!"

Или перенаправить только для определенного print оператора:

print >>sys.stderr, "Hello World!"

Чтобы сбросить стандартный вывод, вы можете просто сделать:

sys.stdout = sys.__stdout__
...