Отключить буферизацию вывода



включена ли буферизация вывода по умолчанию в интерпретаторе 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 программно во время выполнения?

531   15  

15 ответов:

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

вы можете пропустить буферизацию для целого процесс python с использованием " python-u" (или#!/ usr / bin / env python-u etc) или установка переменной среды ПИТОНУНБУФФЕР.

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

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'
# 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? или функция печати Python, которая очищает буфер при его вызове?, но так как они были помечены как дубликаты этого (с чем я не согласен), я отвечу здесь.

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

print('Hello World!', flush=True)

Да, это так.

вы можете отключить его в командной строке с помощью переключателя "-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"])

без сохранения старой системы.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.мусор-это не такая хорошая идея, потому что именно там помещаются несвободные циклы, и вы можете проверить их.)

следующие работы в 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)

это относится к ответу Cristóvão D. Sousa, но я пока не могу комментировать.

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

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

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

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

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

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

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

вы также можете запустить Python с stdbuf утилиты:

stdbuf -oL python <script>

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

один из способов получить unbuffered выход будет использовать sys.stderr вместо sys.stdout или просто позвонить sys.stdout.flush() явное принудительное выполнение записи.

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

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

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

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

для сброса stdout вы можете просто сделать:

sys.stdout = sys.__stdout__

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

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

    for line in sys.stdin:
    ...

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

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

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

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

вы не можете волшебным образом изменить системный stdout; так как он поставляется в вашу программу python ОС.

можно переопределить только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.

Comments

    Ничего не найдено.