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