【问题标题】:I/O to Screen/Standard OutputI/O 到屏幕/标准输出
【发布时间】:2012-12-25 15:41:12
【问题描述】:

我注意到,在我编写的任何程序中,如果我在监视器上进行大量打印(即printffprintf (stderr, "...")),执行时间会明显变慢。

我认为由于磁盘的物理限制,写入磁盘会很慢。我不确定为什么打印到屏幕会显着减慢程序速度。

【问题讨论】:

  • 用户和内核空间之间的切换,流水线等。
  • 基本上是因为stdio(大部分)是行缓冲的,并且每次写入都会调用系统调用。顺便说一句:在虚拟终端上,终端仿真器也会消耗很多周期。在多 CPU 机器上,一个 CPU 忙于滚动和缓冲,而另一个 CPU 则为其提供输出。

标签: c io


【解决方案1】:

向终端写入并不是很快,也不是为了快速而设计的,因为通常进入标准输出的唯一内容是受用户阅读速度限制的信息片段。

当您在例如终端上写信时。 linux,会发生以下事情(也许)。在每两个连续步骤之间调用内核:

  1. 您的程序发出写入系统调用来写入数据。
  2. 内核恢复您的终端模拟器并产生写入终端设备的数据
  3. 终端模拟器呈现其框架的新状态并将其发送到 X 服务器
  4. X 服务器操作内存映射的显示区域
  5. 内核告诉您的显卡交换缓冲区

这些步骤很多......由于终端输出通常只是行缓冲,所以这种情况经常发生。

【讨论】:

  • 你能描述一下你(和这个线程上的其他人)所说的“行缓冲”是什么意思吗?还有其他类型的缓冲吗?什么是终端输出上下文中的缓冲?
  • @poundifdef line-buffered 表示:当您调用写入行缓冲输出的函数时,数据存储在缓冲区中,如果缓冲区已满或有换行符则写入.
【解决方案2】:

根据屏幕的类型、屏幕的大小、显卡或任何输出经过,是的,打印内容会显着增加执行时间。很可能打印到磁盘实际上更快 - 磁盘每秒可能需要几兆字节(理论上在现代 SATA 驱动器上大约 300-600MB/s,但实际上,迟早会比这慢,因为磁盘实际上需要将数据移动到磁盘内的盘片上——但它们也有很大的缓存,因此写入 16MB 或 32MB 可能需要相当长的时间)。尝试在您的代码中添加一些时间戳(如果您还没有),并将myprogmyprog > filemyprog > /dev/null(或NUL:如果您是Windows)进行比较,看看哪个需要更多时间-我敢打赌一个进入屏幕 - 写入空设备是最快的,但只有一点点。

打印到屏幕的最大问题是滚动 - 这意味着“随机播放所有内容”,即使使用智能硬件,也可能需要相当多的像素来随机播放。请记住,现代显卡更倾向于绘制 3D,这与滚动 2D 文本屏幕的方式完全不同。

当然,最重要的是,您的应用程序本身需要更多时间,因为您正在调用 printf 或类似的函数,这些函数并不完全是微不足道的函数,因此如果您打印很多东西,printf 本身需要一些时间- 对于具有简单代码的程序,这可能是完成实际工作所需时间的 10 倍,即使数据变为“空”。

【讨论】:

    【解决方案3】:

    printf() 在打印到屏幕(终端)时通常是行缓冲的,这会使输出变慢。

    您可以使用 setvbuf() 设置 stdout 的缓冲区大小。

    【讨论】:

    • 所以如果我将它设置为打印每个说,100 行或其他东西,那么它会更快吗?
    • @Kitchi 也许。尝试一次性将数据输出到文件中以获得最佳性能。
    • @Kitchi 很有可能。基本上缓冲输出将避免为每一行调用 printf() 的开销。
    • setvbuf 无助于每行调用 printf 的开销。它将提高一次性发送到屏幕/磁盘的数据量,因为更多的数据被一次性发送。但是 printf 本身仍然会做同样的事情 - 这就像将一个空啤酒罐带到回收箱或拿一个袋子一次性收集所有东西之间的区别。但是你仍然需要拿起每个啤酒罐。
    猜你喜欢
    • 2017-09-20
    • 2012-01-20
    • 1970-01-01
    • 1970-01-01
    • 2016-02-20
    • 2012-08-25
    • 2012-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多