为什么C++词法分析器中ifstream逐字符读取比stringstream遍历更快?
性能差异原因
- 核心问题出在你
stringstream方案的错误使用上:std::stringstream::str()方法的返回值是整个缓冲区内容的临时拷贝字符串,而非原缓冲区的引用。你每次调用buffer.str()[counter++]都会完整复制一次整个加载的文件内容,再取对应位置的字符,用完就销毁临时字符串,产生极高的冗余拷贝开销。 - 你在字符读取、空格跳过、边界判断三个位置都反复调用
buffer.str(),文件越大单次拷贝开销越高,调用次数随token数量线性增长,最终整体耗时呈现超线性上涨,和你测试结果完全吻合:800token时拷贝开销已经是ifstream方案的百倍,21000token时更是达到了数万倍的开销差。 - 另外ifstream本身默认有内核级的页缓存和用户态的缓冲区,小文件读取时几乎不会真的触发磁盘IO,性能本来就不低,和你预期的“磁盘IO开销高”的场景不符。
内存读取方案优化建议
你原本的内存读取思路是对的,只要修正错误用法就能得到远高于ifstream的性能,优化步骤如下:
- 文件加载阶段就把所有内容一次性读取到一个
std::string类型的类成员变量(比如叫file_buf)中,不需要留存stringstream - 直接用
file_buf[counter++]访问字符,或者用const char* buf_ptr = file_buf.data()存首地址,用指针偏移*(buf_ptr + counter++)访问,性能更高 - 边界判断直接用
counter > file_buf.size(),不要重复生成字符串
优化后示例代码
// 类成员提前加载文件内容:std::string file_buf; inline void Scanner::NextChar() { unscannedChar = file_buf[counter++]; currentCol++; while (unscannedChar == ' ') { unscannedChar = file_buf[counter++]; currentCol++; } if (counter > file_buf.size()) { unscannedChar = std::char_traits<char>::eof(); } }
这个优化后的版本性能会比ifstream方案高出至少一个数量级。
内容的提问来源于stack exchange,提问作者Algo
相关产品推荐
相关产品推荐

