Отключить буферизацию вывода
включена ли буферизация вывода по умолчанию в интерпретаторе Python для sys.stdout?
если ответ положительный, каковы все способы его отключить?
предложения до сих пор:
- использовать
-uпереключатель командной строки - обертывание
sys.stdoutв объекте, который сбрасывается после каждой записи - Set
PYTHONUNBUFFEREDenv var sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
есть ли другой способ установить какой-либо глобальный флаг sys/sys.stdout программно во время выполнения?
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) что это отвечает на вопрос только частично, поскольку он не перенаправляет все выходные данные. Но я думаю,
stdout/stderrв python, так что эти 2 строки охватывают, вероятно, большинство случаев использования.обратите внимание (b), что он работает только в модуле/скрипте, где вы его определили. Это может быть хорошо при написании модуля, так как он не связывается с
sys.stdout.Python 2 не дает
flushаргумент, но вы можете эмулировать Python 3-type
Да, он включен по умолчанию. Вы можете отключить его с помощью параметра-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 >>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)
(я опубликовал комментарий, но он как-то потерялся. Итак, еще раз:)
как я заметил, CPython (по крайней мере, на Linux) ведет себя по-разному в зависимости от того, где вывод идет. Если он переходит к tty, то выход сбрасывается после каждого '
\n'
если он идет в канал / процесс, то он буферизуется, и вы можете использоватьflush()решений или - u рекомендовано выше.немного связано с выходом буферизация:
Если вы перебираете строки во входных данных с помощью
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