Я всегда был поражен / расстроен тем, сколько времени требуется, чтобы просто вывести на терминал оператор 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