【发布时间】:2010-12-22 09:28:22
【问题描述】:
我有一个小 C 程序来计算哈希(用于哈希表)。我希望代码看起来很干净,但有一些与它无关的东西困扰着我。
我可以在大约 0.2-0.3 秒内轻松生成大约一百万个哈希(以 /usr/bin/time 为基准)。但是,当我在 for 循环中对它们进行 printf() 处理时,程序会减慢到大约 5 秒。
- 这是为什么呢?
- 如何让它更快? mmapp() 可能是标准输出?
- stdlibc 在这方面是如何设计的,如何改进?
- 内核如何更好地支持它?需要如何修改才能使本地“文件”(套接字、管道等)的吞吐量真正快速?
我期待着有趣而详细的回复。谢谢。
PS:这是一个编译器构建工具集,所以不要害羞地进入细节。虽然这与问题本身无关,但我只想指出我感兴趣的细节。
附录
我正在为解决方案和解释寻找更多程序化方法。确实,管道可以完成这项工作,但我无法控制“用户”的工作。
当然,我现在正在进行测试,“普通用户”不会这样做。但这并没有改变一个简单的 printf() 会减慢进程的事实,这是我试图找到最佳编程解决方案的问题。
附录 - 惊人的结果
参考时间是 TTY 内的普通 printf() 调用,大约需要 4 分 20 秒。
在 /dev/pts(例如 Konsole)下进行测试可将输出加速到大约 5 秒。
在我的测试代码中使用 setbuffer() 到 16384 的大小大约需要相同的时间,对于 8192 几乎相同:大约 6 秒。
setbuffer() 显然在使用时没有任何效果:它需要相同的时间(在 TTY 上大约 4 分钟,在 PTS 上大约 5 秒)。
令人惊讶的是,如果我在 TTY1 上开始测试,然后切换到另一个 TTY,它确实需要与在 PTS 上相同:大约5 秒。
结论:内核做了一些与可访问性和用户友好性有关的事情。呵呵!
通常,无论您是在 TTY 处于活动状态时盯着它看,还是切换到另一个 TTY,它都应该同样慢。
教训:运行输出密集型程序时,切换到另一个 TTY!
【问题讨论】:
-
如果你将输出重定向到/dev/null,那么你的程序有多快?
-
@ammoQ:与重定向到任何常规文件时一样快:大约 0.5 秒。
-
这不是一件“简单”的事情。 I/O 通常比直接 CPU 计算和总线操作慢几个数量级,实现它应该不会那么令人惊讶。
-
令人惊讶的是,如果您在进程执行并显示某些内容的同时查看 TTY,则执行需要 4 分钟。如果不看 TTY,则需要 5 秒。
-
Flavius:那是因为在显示 TTY 时,每一行都需要向上滚动整个屏幕。屏幕上的每个字符单元都映射到屏幕缓冲区中的特定位置 - 因此移动字符意味着在屏幕缓冲区中移动字节。在 80 列控制台上,这意味着向上移动 24 行基本上是
memmove几乎 2k - 为您输出的每一行完成。
标签: c performance linux-kernel stdout glibc