写入stdout能否以某种方式加速?
我编写了一个脚本(本问题底部的“
print_timer.py
”)来比较向stdout、文件和将stdout重定向到/dev/null
时写入100k行的时间。以下是计时结果:$ 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
因此,这不是Python的技巧,只是终端。我一直知道将输出转储到/dev/null可以加快速度,但从未想过它如此重要!
令我惊奇的是tty有多慢。如何才能使写入物理磁盘比写入“屏幕”(可能是全RAM操作)更快,并且实际上与使用/dev/null简单转储一样快?
此链接讨论了终端将阻止I/O,以便“解析[输入],更新其帧缓冲区,与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倍),但这并没有改变我的问题。它只是在我的问题上增加了,因为我不明白为什么终端屏幕渲染会减慢写入stdout的应用程序。为什么我的程序需要等待屏幕渲染才能继续?
所有终端/tty应用程序都不是平等创建的吗?我还没有尝试过。真的很像终端应该能够缓冲所有传入的数据,无形地解析/渲染它,并以合理的帧速率仅呈现当前屏幕配置中可见的最新块。所以如果我可以在约0.1秒内写入+ fsync到磁盘,终端应该能够以相同的顺序完成相同的操作(在执行此操作时可能会更新几次屏幕)。
我仍然希望有一个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