编译器是如何如此有效地优化getline()的
How does the compiler optimize getline() so effectively?
我知道编译器的许多优化可能相当深奥,但我的例子非常简单,我想看看我是否能理解,是否有人知道它可以做什么。
我有一个500 mb的文本文件。我声明并初始化一个fstream:
std::fstream file(path,std::ios::in)
我需要按顺序阅读这个文件。它是用制表符分隔的,但字段长度未知,并且逐行变化。我需要对每一行进行的实际解析只增加了很少的时间(这真的让我很惊讶,因为我在getline的每一行上都进行了string::find。我觉得这会很慢)。
一般来说,我想在每一行中搜索一个字符串,并在找到它时中止循环。为了自己的好奇心,我还让它递增并吐出行号,我确认这只增加了很少的时间(5秒左右),让我看到它是如何越过短线并在长线上减速的。
我有作为标记eof的唯一字符串的文本,所以它需要搜索每一行。我在手机上做这件事,所以我为格式问题道歉,但这很简单。我有一个函数,将我的fstream作为引用,将要查找的文本作为字符串,并返回std::size_t。
long long int lineNum = 0;
while (std::getline (file, line))
{
pos = line.find(text);
lineNum += 1;
std::cout << std::to_string(lineNum) << std::endl;
if (pos != -1)
return file.tellg():
}
return std::string::npos;
编辑:灵犀指出这里不需要to_string,谢谢。如前所述,完全省略行号计算和输出可以节省几秒钟的时间,在我的预优化示例中,这只占总数的一小部分。
这成功地贯穿了每一行,并在408秒内返回终点位置。尝试将文件放在字符串流中,或者省略整个循环中的所有内容,我的改进微乎其微(直到最后都是getline,没有检查、搜索或显示)。此外,为字符串预先预留一个巨大的空间也无济于事。
似乎getline完全是驱动程序。然而如果我使用/O2标志(MSVC++)进行编译,我会得到快得离谱的26秒。此外,长线与短线之间没有明显的减速。显然,编译器正在做一些非常不同的事情。我没有抱怨,但对它是如何实现的有任何想法吗?作为一个练习,我想在编译器优化之前让我的代码执行得更快。
我打赌这与getline处理字符串的方式有关。只为字符串保留整个文件大小,并逐字符读取,在通过/n时递增行号,会更快吗(唉,暂时无法测试)?此外,编译器会使用类似mmap的东西吗?
更新:我今晚回家后会发布代码。看起来只是关闭运行时检查就把执行时间从400秒降到了50秒!我尝试使用原始c风格的数组执行相同的功能。我不是很有经验,但将数据转储到一个字符数组中,并在其中循环查找换行符或目标字符串的第一个字母,这很容易。
即使在完全调试模式下,它也能在54秒内完成并正确找到字符串。取消检查时为26秒,优化后为20秒。所以,从我非正式的、特别的实验来看,字符串和流函数似乎受到了运行时检查的伤害?我回家后会再次检查。
这种显著加速的原因是iostream类层次结构基于模板(std::ostream
实际上是一个名为std::basic_ostream
的模板的typedef),并且它的许多代码都在头中。C++iostream需要几个函数调用来处理流中的每个字节。然而,这些函数中的大多数都相当琐碎。通过启用优化,这些调用中的大多数都是内联的,这向编译器暴露了这样一个事实,即std::getline
本质上是将字符从一个缓冲区复制到另一个缓冲区时,直到它找到一条换行符——通常这是在几层函数调用下"隐藏"的。这可以进一步优化,将每个字节的开销减少几个数量级。
缓冲行为实际上在优化版本和非优化版本之间不会发生变化,否则速度会更高。
- Seg Fault Issue C++ (file IO / getline)
- 空基优化子对象的地址
- 关闭||运算符优化
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 当用户键入分隔符时,停止getline()输入
- 返回值优化:显式移动还是隐式
- 人脸跟踪arduino代码的优化
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- getline() 的原型/库是什么;
- 纯函数,为什么没有优化
- 错误 没有与参数列表匹配的重载函数"getline"实例
- 为什么大多数 pair 实现默认不使用压缩(空基优化)?
- 如何以优化的方式同时迭代两个间距不相等的数组
- 如何在 c++ 中使用 ',' 作为 getline 分隔符
- 错误:调用'getline'没有匹配函数
- 如何在 c++ 中使用 getline 从文件中读取字符串?
- 小字符串优化(调试与发布模式)
- 浮点定向舍入和优化
- Visual Studio 调试优化如何工作?
- 编译器是如何如此有效地优化getline()的