编译器如何有效地优化getline()?

moc*_*att 5 c++ optimization fileinputstream

我知道很多编译器的优化可能相当深奥,但我的例子非常简单,我想看看我能理解,如果有人知道它可以做什么.

我有一个500 MB的文本文件.我声明并初始化一个fstream:

std::fstream file(path,std::ios::in)
Run Code Online (Sandbox Code Playgroud)

我需要按顺序读取文件.它的制表符分隔,但字段长度未知,并且逐行变化.我需要对每一行进行的实际解析为总数增加了很少的时间(这真让我感到惊讶,因为我在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;
Run Code Online (Sandbox Code Playgroud)

编辑:lingxi指出在这里没有必要使用to_string,谢谢.如上所述,完全省略行号计算和输出可以节省几秒钟,这在我的预优化示例中占总数的一小部分.

这成功地遍历每一行,并在408秒内返回结束位置.尝试将文件放在字符串流中,或者省略整个循环中的所有内容(只是getline直到结束,没有检查,搜索或显示),我的改进很小.为字符串预留一个巨大的空间也无济于事.

似乎getline完全是驱动程序.但是......如果我使用/ O2标志(MSVC++)进行编译,我可以更快地获得26秒.此外,长线与短线没有明显的减速.很明显,编译器正在做一些非常不同的事情.没有我的抱怨,但有任何想法如何实现?作为练习,我想尝试让我的代码在编译器优化之前更快地执行.

我敢打赌它与getline操纵字符串的方式有关.是否更快(唉不能测试一段时间)只保留字符串的整个文件大小,并按字符读取,当我传递一个/ n时增加我的行号?此外,编译器会使用像mmap这样的东西吗?

更新:我今晚回家时会发布代码.看起来只是关闭运行时检查将执行从400秒降低到50秒!我尝试使用原始c样式数组执行相同的功能.我不是很有经验,但很容易将数据转储到字符数组中,并循环查找换行符或目标字符串的第一个字母.

即使在完全调试模式下,它也会在54秒内正确找到字符串.检查关闭26秒,优化20秒.因此,从我的非正式的临时实验看,字符串和流函数是运行时检查的牺牲品?我再次回到家时会再次检查.

Krz*_*ski 1

这种显着加速的原因是 iostream 类层次结构基于模板(std::ostream实际上是名为 的模板的 typedef std::basic_ostream),并且其许多代码都在标头中。C++ iostream 需要多次函数调用来处理流中的每个字节。然而,大多数这些功能都是相当微不足道的。通过打开优化,大多数调用都是内联的,向编译器暴露这样的事实:std::getline本质上将字符从一个缓冲区复制到另一个缓冲区,直到找到换行符 - 通常这“隐藏”在几层函数调用下。这可以进一步优化,将每字节的开销减少几个数量级。

缓冲行为实际上在优化版本和非优化版本之间没有变化,否则加速会更高。