Почему печать на стандартный вывод так медленно? Это может быть ускорено?

Я всегда удивлялся / расстраивался из-за того, сколько времени требуется, чтобы просто вывести на терминал оператор print. После недавних мучительно медленных лесозаготовок я решил изучить это и был довольно удивлен, обнаружив, что почтивсе затраченное время ожидает, пока терминал обработает результаты.

Можно ли как-то ускорить запись в stdout?

Я написал сценарий ('print_timer.pyв нижней части этого вопроса) для сравнения времени при записи 100 тыс. строк в стандартный вывод, в файл и с перенаправленным на стандартный вывод/dev/null, Вот результат синхронизации:

$ python print_timer.py
this is a test
this is a test
<snipped 99997 lines>
this is a test
-----
timing summary (100k lines each)
-----
print                         :11.950 s
write to file (+ fsync)       : 0.122 s
print with stdout = /dev/null : 0.050 s

Вот это да. Чтобы убедиться, что python не делает что-то за кулисами, например, узнав, что я переназначил stdout на / dev / null или что-то в этом роде, я сделал перенаправление вне скрипта

$ python print_timer.py > /dev/null
-----
timing summary (100k lines each)
-----
print                         : 0.053 s
write to file (+fsync)        : 0.108 s
print with stdout = /dev/null : 0.045 s

Так что это не трюк с питоном, это просто терминал. Я всегда знал, что вывод данных в / dev / null ускорял процесс, но никогда не думал, что это так важно!

Меня удивляет, насколько медленно работает tty. Как может быть так, что запись на физический диск является ПУТЬ быстрее, чем запись на «экран» (предположительно операционная система все-ОЗУ), и эффективна так же быстро, как простой вывод в мусор с / dev / null?

Эта ссылка говорит о том, как терминал будет блокировать ввод / вывод, чтобы он мог"проанализировать [входные данные], обновить его буфер кадров, связаться с X-сервером, чтобы прокрутить окно и т. д."... но я не до конца понимаю Что может быть так долго?

Я ожидаю, что нет никакого выхода (если не считать более быструю реализацию tty?), Но я бы все-таки спросил.

ОБНОВЛЕНИЕ: после прочтения некоторых комментариев я задумался о том, как сильно влияет размер моего экрана на время печати, и это действительно имеет какое-то значение. Очень медленные цифры выше - мой терминал Gnome взорван до 1920x1200. Если я уменьшу его очень мало, я получу ...

-----
timing summary (100k lines each)
-----
print                         : 2.920 s
write to file (+fsync)        : 0.121 s
print with stdout = /dev/null : 0.048 s

Это, конечно, лучше (~ 4 раза), но не меняет моего вопроса. Это толькодобавляет на мой вопрос, так как я не понимаю, почему рендеринг экрана терминала должен замедлять запись приложения в стандартный вывод. Почему моей программе нужно ждать продолжения рендеринга экрана?

Все терминальные / tty приложения не созданы равными? Я еще не экспериментировал. Мне действительно кажется, что терминал должен иметь возможность буферизовать все входящие данные, анализировать / визуализировать их невидимым образом и отображать только самый последний фрагмент, видимый в текущей конфигурации экрана, с разумной частотой кадров. Поэтому, если я могу записать + fsync на диск за ~ 0,1 секунды, терминал должен быть в состоянии выполнить ту же операцию в каком-то порядке (возможно, с несколькими обновлениями экрана, пока он это делал).

Я все еще надеюсь, что есть параметр tty, который можно изменить со стороны приложения, чтобы сделать это лучше для программиста. Если это строго проблема с терминальным приложением, то, возможно, это даже не относится к StackOverflow?

Что мне не хватает?

Вот программа на python, используемая для генерации времени:

import time, sys, tty
import os

lineCount = 100000
line = "this is a test"
summary = ""

cmd = "print"
startTime_s = time.time()
for x in range(lineCount):
    print line
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

#Add a newline to match line outputs above...
line += "\n"

cmd = "write to file (+fsync)"
fp = file("out.txt", "w")
startTime_s = time.time()
for x in range(lineCount):
    fp.write(line)
os.fsync(fp.fileno())
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

cmd = "print with stdout = /dev/null"
sys.stdout = file(os.devnull, "w")
startTime_s = time.time()
for x in range(lineCount):
    fp.write(line)
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

print >> sys.stderr, "-----"
print >> sys.stderr, "timing summary (100k lines each)"
print >> sys.stderr, "-----"
print >> sys.stderr, summary

Ответы на вопрос(6)

Ваш ответ на вопрос