为了账号安全,请及时绑定邮箱和手机立即绑定

为什么打印到标准输出这么慢?可以加快速度吗?

为什么打印到标准输出这么慢?可以加快速度吗?

幕布斯7119047 2019-12-09 14:36:55
我一直对使用print语句简单地输出到终端需要多长时间感到惊讶/沮丧。在经历了最近令人痛苦的缓慢日志记录之后,我决定进行调查,并惊讶地发现几乎所有的时间都在等待终端处理结果。可以以某种方式加快对stdout的写入速度吗?我编写了一个脚本(print_timer.py此问题底部的' ')来比较将100k行写入stdout,文件以及将stdout重定向到时的时序/dev/null。计时结果如下:$ python print_timer.pythis is a testthis is a test<snipped 99997 lines>this is a test-----timing summary (100k lines each)-----print                         :11.950 swrite to file (+ fsync)       : 0.122 sprint 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 swrite to file (+fsync)        : 0.108 sprint 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 swrite to file (+fsync)        : 0.121 sprint with stdout = /dev/null : 0.048 s那当然更好(〜4倍),但不会改变我的问题。这只会增加我的问题,因为我不明白为什么终端屏幕渲染会减慢应用程序向stdout的写入速度。为什么我的程序需要等待屏幕渲染继续?是否所有创建的终端/ tty应用程序都不相等?我还没有实验。在我看来,终端确实应该能够缓冲所有传入的数据,以不可见的方式解析/渲染它们,并且仅以合理的帧速率渲染在当前屏幕配置中可见的最新块。因此,如果我可以在约0.1秒内将+ fsync写入磁盘,则终端应该能够以该顺序完成相同的操作(在执行此操作时可能需要进行一些屏幕更新)。我仍然希望可以从应用程序端更改tty设置,以使程序员更好地实现此行为。如果严格来说这是终端应用程序问题,那么这可能甚至不属于StackOverflow吗?我想念什么?这是用于生成计时的python程序:import time, sys, ttyimport oslineCount = 100000line = "this is a test"summary = ""cmd = "print"startTime_s = time.time()for x in range(lineCount):    print linet = time.time() - startTime_ssummary += "%-30s:%6.3f s\n" % (cmd, t)#Add a newline to match line outputs above...line += "\n"
查看完整描述

3 回答

?
喵喔喔

TA贡献1735条经验 获得超5个赞

写入物理磁盘比写入“屏幕”(大概是全RAM操作)要快得多,并且实际上与使用/ dev / null转储到垃圾中一样快?


恭喜,您刚刚发现了I / O缓冲的重要性。:-)


磁盘似乎速度更快,因为它具有很高的缓冲能力:write()在将任何内容实际写入物理磁盘之前,所有Python的调用都将返回。(操作系统稍后执行此操作,将成千上万的单个写入合并为一个大而有效的块。)


另一方面,终端几乎不执行缓冲或不执行缓冲:每个人print/ write(line)等待完整的写入(即显示到输出设备)完成。


为了使比较合理,您必须使文件测试使用与终端相同的输出缓冲,可以通过将示例修改为以下操作来做到这一点:


fp = file("out.txt", "w", 1)   # line-buffered, like stdout

[...]

for x in range(lineCount):

    fp.write(line)

    os.fsync(fp.fileno())      # wait for the write to actually complete

我在我的机器上运行了文件写入测试,并通过缓冲在100,000行中也进行了0.05s的测试。


但是,通过上述修改以无缓冲方式写入数据,只需要40秒就可以将1,000行写入磁盘。我放弃了等待100,000行的写操作,但是从以前的内容推论得出,这将花费一个多小时。


这使航站楼的11秒成为现实,不是吗?


因此,要回答您最初的问题,考虑到所有因素,写一个终端实际上非常快,并且没有太多的空间可以使它更快(但是各个终端的工作量有所不同;请参阅Russ对此的评论)回答)。


(您可以像使用磁盘I / O一样添加更多的写缓冲,但是直到缓冲区被刷新后,您才能看到向终端写入的内容。这是一个折衷方案:交互性与大容量效率。)


查看完整回答
反对 回复 2019-12-09
  • 3 回答
  • 0 关注
  • 1025 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信