printf减慢了我的程序

时间:2009-12-02 12:01:02

标签: c performance linux-kernel stdout glibc

我有一个小的C程序来计算哈希值(用于哈希表)。我希望代码看起来很干净,但有一些与它无关的东西让我烦恼。

我可以在大约0.2-0.3秒内轻松生成大约一百万个哈希值(以/ usr / bin / time为基准)。但是,当我在for循环中使用printf()时,程序会减慢到大约5秒钟。

  1. 这是为什么?
  2. 如何让它更快? mmapp()ing stdout也许?
  3. stdlibc如何针对此进行设计,以及如何改进?
  4. 内核如何更好地支持它?如何修改本地“文件”(套接字,管道等)的吞吐量真的很快?
  5. 我期待着有趣而详细的回复。感谢。

    PS:这是针对编译器构造工具集的,所以不要害羞进入细节。虽然这与问题本身无关,但我只想指出细节让我感兴趣。

    附录

    我正在寻找更多解决方案和解释的程序方法。确实,管道工作起了作用,但我无法控制“用户”的作用。

    当然,我现在正在进行测试,“普通用户”不会这样做。但这并没有改变一个简单的printf()减慢进程的事实,这是我试图找到最佳编程解决方案的问题。


    附录 - 惊人的结果

    参考时间适用于TTY内的普通printf()调用,大约需要4分钟20秒。

    在/ dev / pts(例如Konsole)下进行测试可将输出速度提高到约5秒。

    在我的测试代码中使用setbuffer()大小为16384时需要大约相同的时间,对于8192大约相同:大约6秒。

    setbuffer()在使用时显然没有效果:它需要相同的时间(在TTY上大约4分钟,在PTS上大约5秒)。

    令人惊讶的是,如果我在TTY1上开始测试然后切换到另一个TTY ,它确实与PTS上的相同:关于5秒。

    结论:内核做了一些与可访问性和用户友好性有关的事情。 HUH!

    通常情况下,无论你在TTY活动时盯着TTY,还是切换到另一个TTY,它都应该同样慢。


    课程:运行输出密集型程序时,切换到另一个TTY!

9 个答案:

答案 0 :(得分:31)

无缓冲输出非常慢。

默认情况下stdout是完全缓冲的,但是当连接到终端时,stdout是无缓冲的或行缓冲的。

尝试使用stdout启用setvbuf()的缓冲,如下所示:

char buffer[8192];

setvbuf(stdout, buffer, _IOFBF, sizeof(buffer));

答案 1 :(得分:14)

您可以将字符串存储在缓冲区中,并在缓冲区已满时将其输出到文件(或控制台)或定期输出。

如果输出到控制台,滚动通常是一个杀手。

答案 2 :(得分:9)

如果你是printf()到控制台,它通常非常慢。我不确定为什么,但我相信它不会返回,直到控制台以图形方式显示输出的字符串。另外,你不能mmap()到stdout。

写入文件应该快得多(但仍然比计算散列慢几个数量级,所有I / O都很慢)。

答案 3 :(得分:7)

您可以尝试将shell中的输出从控制台重定向到文件。使用此功能,可以在几秒钟内创建大小为千兆字节的日志。

答案 4 :(得分:6)

  1. 与之相比,I / O总是很慢 直接计算。该系统有 等待更多的组件 可用以使用它们。它 然后必须等待回应 在它可以继续之前。反过来 如果它只是计算,那么它就是 只有真正移动数据之间 RAM和CPU寄存器。

  2. 我没有对此进行测试,但将哈希附加到字符串上可能会更快,然后只需在末尾打印字符串。虽然如果你使用C而不是C ++,这可能会很痛苦!

  3. 我害怕,3和4超出我的范围。

答案 5 :(得分:4)

  1. 为什么不按需创建字符串而不是在构造点?在一秒钟内输出40个数据屏幕没有意义,你怎么可能阅读它?为什么不根据需要创建输出,只显示最后一个屏幕,然后根据需要用户滚动???

  2. 为什么不使用sprintf打印到字符串然后在内存中构建所有结果的连接字符串并在结尾打印?

  3. 通过切换到sprintf,您可以清楚地看到格式转换花费了多少时间,以及将结果显示到控制台并适当更改代码所花费的时间。

  4. 控制台输出定义很慢,创建散列只能操作几个字节的内存。控制台输出需要经过操作系统的许多层,一旦最终到达显示驱动程序(可能是9600波特设备),它将具有处理线程/进程锁定等的代码!或大型位图显示,滚动屏幕等简单功能可能涉及操作兆字节的内存。

答案 6 :(得分:4)

由于I / O总是比CPU计算慢得多,因此您可以先将所有值存储在最快的I / O中。因此,如果你有足够的RAM,请使用RAM,如果没有,则使用Files,但它比RAM慢得多。

现在可以在其他线程之后或之后并行打印出值。因此,计算线程可能不需要等到printf返回。

答案 7 :(得分:4)

我很久以前就发现了using this technique应该是显而易见的事情。 不仅I / O速度慢,尤其是控制台,但格式化十进制数也不快。如果您可以将二进制数字放入大缓冲区,并将其写入文件,您会发现它更快。

此外,谁会阅读它们?如果没有人需要阅读所有这些内容,那么以人类可读的格式打印它们毫无意义。

答案 8 :(得分:2)

我猜终端类型正在使用一些缓冲输出操作,因此当你执行printf时,它不会以分裂微秒输出,而是存储在终端子系统的缓冲存储器中。

这可能会受到可能导致速度减慢的其他因素的影响,也许除了您的程序之外,还会运行内存密集型操作。简而言之,太多的事情可能同时发生,分页,交换,另一个进程的繁重i / o,使用的内存配置,内存升级等等。

最好将字符串连接到达到某个限制,然后在达到某个限制时,将其全部写出来。甚至使用pthread来执行所需的流程执行。

<强>编辑: 至于2,3它超出了我。对于4,我不太熟悉Sun,但是知道并且已经搞乱了Solaris,可能有一个内核选项来使用虚拟tty ..我会承认它已经有一段时间了用内核配置并重新编译它。因此,我的记忆在这方面可能并不是很好,请根据选项查看。

user@host:/usr/src/linux $ make; make menuconfig **OR kconfig if from X**

这将激活内核菜单,在设备子树下查看视频设置部分。

<强>编辑: 但是你通过在proc文件系统中添加一个文件(如果确实存在这样的东西),或者可能是一个传递到内核中的开关,这是一个调整你进入内核,这样的事情(这是富有想象力的,并不意味着它实际存在),fastio

希望这有帮助, 最好的祝福, 汤姆。