Вопрос

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

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

Предложений пока нет:

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

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

Это было полезно?

Решение

От Ответ Магнуса Ликки в списке рассылки:

Вы можете пропустить буферизацию для всего процесса на Python используя "python -u" (или #!/usr/bin/env python -u и т.д.) Или установив переменную среды PYTHON БЕЗ БУФЕРА.

Вы также можете заменить sys.stdout на какой-нибудь другой поток, подобный оболочке, который выполняет сброс после каждого вызова.

class Unbuffered(object):
   def __init__(self, stream):
       self.stream = stream
   def write(self, data):
       self.stream.write(data)
       self.stream.flush()
   def writelines(self, datas):
       self.stream.writelines(datas)
       self.stream.flush()
   def __getattr__(self, attr):
       return getattr(self.stream, attr)

import sys
sys.stdout = Unbuffered(sys.stdout)
print 'Hello'

Другие советы

Я бы предпочел изложить свой ответ в Как очистить вывод Python print? или в Функция печати Python, которая очищает буфер при его вызове?, но поскольку они были помечены как дубликаты этого (с чем я не согласен), я отвечу на него здесь.

Поскольку Python 3.3 print() поддерживает аргумент ключевого слова "flush" (смотрите документацию):

print('Hello World!', flush=True)
# reopen stdout file descriptor with write mode
# and 0 as the buffer size (unbuffered)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

Реквизиты:"Себастьян", где-то в списке рассылки Python.

правка третьей стороны

Не поддерживается в последних версиях Python 3

Да, это так.

Вы можете отключить его в командной строке с помощью переключателя "-u".

В качестве альтернативы, вы могли бы вызывать .flush() в sys.stdout при каждой записи (или оборачивать его объектом, который делает это автоматически)

def disable_stdout_buffering():
    # Appending to gc.garbage is a way to stop an object from being
    # destroyed.  If the old sys.stdout is ever collected, it will
    # close() stdout, which is not good.
    gc.garbage.append(sys.stdout)
    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

# Then this will give output in the correct order:
disable_stdout_buffering()
print "hello"
subprocess.call(["echo", "bye"])

Без сохранения старого sys.stdout функция disable_stdout_buffering() не является идемпотентной, и множественные вызовы приведут к ошибке, подобной этой:

Traceback (most recent call last):
  File "test/buffering.py", line 17, in <module>
    print "hello"
IOError: [Errno 9] Bad file descriptor
close failed: [Errno 9] Bad file descriptor

Другая возможность заключается в:

def disable_stdout_buffering():
    fileno = sys.stdout.fileno()
    temp_fd = os.dup(fileno)
    sys.stdout.close()
    os.dup2(temp_fd, fileno)
    os.close(temp_fd)
    sys.stdout = os.fdopen(fileno, "w", 0)

(Добавление в gc.garbage - не такая уж хорошая идея, потому что именно там помещаются несвободные циклы, и вы можете захотеть проверить их наличие.)

Это относится к Кристовану Д.Ответ Соузы, но я пока не могу комментировать.

Простой способ использования flush ключевое слово аргумент из Python 3 для того, чтобы всегда иметь небуферизованный вывод - это:

import functools
print = functools.partial(print, flush=True)

после этого print всегда будет очищать выходные данные напрямую (за исключением flush=False дается).

Обратите внимание, (a) что это отвечает на вопрос лишь частично, поскольку не перенаправляет весь вывод.Но я думаю, что print является наиболее распространенным способом создания выходных данных для stdout/stderr в python, таким образом, эти 2 строки охватывают, вероятно, большинство вариантов использования.

Обратите внимание (b), что это работает только в модуле / скрипте, в котором вы его определили.Это может быть полезно при написании модуля, поскольку это не мешает sys.stdout.

Python 2 не обеспечивает flush аргумент, но вы могли бы эмулировать Python 3-го типа print функционируйте так, как описано здесь https://stackoverflow.com/a/27991478/3734258 .

Следующее работает в Python 2.6, 2.7 и 3.2:

import os
import sys
buf_arg = 0
if sys.version_info[0] == 3:
    os.environ['PYTHONUNBUFFERED'] = '1'
    buf_arg = 1
sys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg)
sys.stderr = os.fdopen(sys.stderr.fileno(), 'a+', buf_arg)

Да, он включен по умолчанию.Вы можете отключить его, используя опцию -u в командной строке при вызове python.

Вы также можете запустить Python с помощью stdbuf полезность:

stdbuf -oL python <script>

Это можно переопределить Только write способ получения sys.stdout с тем , кто зовет flush.Предлагаемая реализация метода приведена ниже.

def write_flush(args, w=stdout.write):
    w(args)
    stdout.flush()

Значение по умолчанию w аргумент сохранит первоначальный вид write ссылка на метод. После write_flush определяется, исходное write может быть переопределен.

stdout.write = write_flush

Код предполагает, что stdout импортируется таким образом from sys import stdout.

Вы также можете использовать 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)

Вариант, который работает без сбоев (по крайней мере, в 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)

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

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

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

    for line in sys.stdin:
    ...

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

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

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

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

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

Одним из способов получить небуферизованный вывод было бы использовать 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__

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

_orig_print = print

def print(*args, **kwargs):
    _orig_print(*args, flush=True, **kwargs)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top