C:为什么fprintf(stdout,……)这么慢?

我仍然经常使用控制台输出来获取我的代码中发生的事情。 我知道这可能有点老式,但我也用它来“管道”stdout到日志文件等。

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

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

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

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

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

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

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

这是很多东西,以确保控制台输出是“非阻塞”。 但结果并不算太糟糕。 我的主程序可以在几微秒内编写复杂的fprintf(stdout,…)。

也许我早些时候应该问:是否有其他(更容易!)的方式来获得非阻塞控制台输出?

我认为时间问题与控制台默认为线路缓冲这一事实有关。 这意味着每次向它写一个'\n'字符时,整个输出缓冲区就会被发送到控制台,这是一个相当昂贵的操作。 这是您为直接在输出中显示的行支付的价格。

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

在第一次写入控制台之前进行此调用:

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

单个写入的时间应该会改善,但输出不会立即出现在控制台中。 这对调试来说不太有用,但时间会有所改善。 如果你设置一个在常规时间间隔内调用fflush(stdout)的线程,比如每秒一次,你应该在单个写操作的性能和编写输出的程序之间的延迟和你可以的时间之间得到合理的平衡。实际上在控制台上看到它。