12

我仍然经常使用控制台输出来了解我的代码中发生了什么。我知道这可能有点过时了,但我也用它来将标准输出“管道”到日志文件等中。

但是,事实证明,控制台的输出由于某种原因变慢了。我想知道是否有人可以解释为什么控制台窗口的 fprintf() 似乎有点阻塞。

到目前为止我所做/诊断的事情:

  1. 我测量了一个简单的 fprintf(stdout,"quick fprintf\n"); 它需要的时间:0.82ms(平均)。这被认为太长了,因为 avsprintf_s(...)在几微秒内将相同的输出写入字符串。因此,必须有一些专门针对控制台的阻塞。

  2. 为了摆脱阻塞,我曾经vsprintf_s(...)将输出复制到类似 fifo 的数据结构中。数据结构受临界区对象保护。然后,一个单独的线程通过将排队的输出放到控制台来取消数据结构的排队。

  3. 通过引入管道服务,我可以获得进一步的改进。我的程序的输出(应该在控制台窗口中结束)按照以下方式进行:

    • Avsprintf_s(...)将输出格式化为简单的字符串。
    • 字符串被排队到类似fifo的数据结构中,例如链表结构。此数据结构受临界区对象的保护。
    • 第二个线程通过将输出字符串发送到命名管道来使数据结构出队。
    • 第二个进程读取命名管道并将字符串再次放入类似 fifo 的数据结构中。这是使读数远离控制台的阻塞输出所必需的。读取过程在读取命名管道时速度很快,并持续监控管​​道缓冲区的填充水平。
    • 第二个进程中的第二个线程最终将数据结构出列fprintf(stdout,...)到控制台。

所以我有两个进程,每个进程至少有两个线程,它们之间有一个命名管道,管道两侧都有类似 fifo 的数据结构,以避免在管道缓冲区已满时阻塞。

要确保控制台输出是“非阻塞”的,就需要做很多事情。但结果还不错。我的主程序可以在几微秒内编写复杂的 fprintf(stdout,...)。

也许我应该早点问:有没有其他(更简单!)的方式来获得非阻塞控制台输出?

4

1 回答 1

13

我认为时间问题与默认情况下控制台是行缓冲的事实有关。这意味着每次您向其中写入一个'\n'字符时,您的整个输出缓冲区都会被发送到控制台,这是一个相当昂贵的操作。这是您为使该行立即出现在输出中所支付的价格。

您可以通过将缓冲策略更改为完全缓冲来更改此默认行为。结果是输出将以与缓冲区大小相等的块发送到控制台,但单个操作将更快地完成。

在您首次写入控制台之前进行此调用:

char buf[10000];
setvbuf(stdout, buf, _IOFBF, sizeof(buf));

个别写入的时间应该会有所改善,但输出不会立即出现在控制台中。这对调试不是很有用,但时序会有所改善。如果您设置一个fflush(stdout)定期调用的线程,例如每秒一次,您应该在单个写入的性能和程序写入输出之间的延迟和您可以实际看到它的时间之间取得合理的平衡控制台。

于 2012-07-19T10:32:09.607 回答