iostream的输入输出为什么这么慢
-
提问:iostream的cout与cin对比stdio的printf和scanf在速度上慢一个量级,产生这种情况的原因是实现上iostream就效率低下吗?
-
回答:并不是这样的,iostream的效率低主要归结于业务逻辑上的两处实现细节。一是iostream会与stdio进行同步;二是iostream会提供flush操作,供用户进行缓冲区刷新。这两点为了提升用户体验而牺牲了效率,以下我们具体探讨这两点优化的内容,以及如何关闭这两处优化,从而提升效率。
1. 与stdio输入输出的同步
std::ios::sync_with_stdio(bool)
控制iostream与stdio是否同步,iostream与stdio输入输出系统都实现了缓冲区的优化,这个开关控制两个缓冲区在输入时的同步检测,默认情况下打开。- 两个缓冲区之间的同步是iostream对stdio进行的,也就是同步的开销全部产生在iostream的cout与cin上,这会极大的降低cout与cin的效率,在使用上iostream会比stdio慢一个量级。因此如果在编写小型项目,或确定项目中不会同时使用iostream和stdio的输出输出接口时,可以用
std::ios::sync_with_stdio(false)
关闭两个库的同步操作,提升cout与cin的效率。
2. 避免频繁的flush操作
- iostream的缓冲区默认会在存满的时候自动清空,因此如果缓冲区还没满我们就不能看到内容,这对用户来说当然很痛苦。iostream提供了
std::flush
进行手动的缓冲区清空操作,这样用户就美滋滋的看到自己的输出了。 - 但是flush是有时间上的代价的,开放flush的权限给用户,就可能导致用户过于频繁的进行flush操作,从而毁灭iostream的效率。尤其是用户不经意间的flush。
众所周知<< std::endl;
==<< '\n' << std::flush;
,当用户频繁地在循环中输出单个字符并endl的时候,他并不知道自己给cpu带来了多大的麻烦。因此在追求效率的时候请慎用endl,改为在需要的时候手动flush。 - 在请求用户输入的时候,程序员通常会展示输入提示语。然而如果你写的 “请输入您的姓名” 停留在缓冲区,你可能会收获一名从茫然慢慢到愤怒的用户。为了避免这种悲剧的发生,iostream聪明的为cin操作加上了前置的flush,每当你使用cin时库函数会自动的帮你清空缓冲区,从而使客户满意。这种操作当然也会有效率上的悲剧,我们希望避免。如果你不需要使用前置flush功能只需要调用
std::cin.tie(0)
即可解除这种操作,提升cin的效率。
总结
关闭这两处后再进行测试iostream的输入输出效率已经和stdio不相上下了,甚至在某些较大的测试集上效率超过了stdio,因此请不要再说iostream慢,他只是比较体贴。
发表评论