c++ - 为什么逐个字符地读取字符比遍历整个文件字符串要快?
问题描述
我有一个词法分析器,它逐个字符地使用文件,寻找标记。我尝试了两种方法NextChar()
,第一种直接从ifstream
through读取ifstream::get(ch)
,第二种将整个文件加载到 astd::stringstream
中以避免磁盘 I/O 开销。
获取()方法:
inline void Scanner::NextChar()
{
inputStream.get(unscannedChar);
currentCol++;
while (unscannedChar == ' ')
{
inputStream.get(unscannedChar);
currentCol++;
}
if (inputStream.eof()) {
unscannedChar = std::char_traits<char>::eof();
}
}
stringstream
方法:虽然加载文件stringstream
不需要时间,但索引非常慢。
inline void Scanner::NextChar()
{
unscannedChar = buffer.str()[counter++];
currentCol++;
while (unscannedChar == ' ')
{
unscannedChar = buffer.str()[counter++];
currentCol++;
}
if (counter > buffer.str().size())
{
unscannedChar = std::char_traits<char>::eof();
}
}
我预计第二种方法会快得多,因为它迭代的是内存中的字符而不是磁盘上的字符,但我错了,这是我的一些测试:
| tokens | ifstream::get() | stringstream::str()[] |
|-------- |----------------- |----------------------- |
| 5 | 0.001 (sec) | 0.001 (sec) |
| 800 | 0.002 (sec) | 0.295 (sec) |
| 21000 | 0.044 (sec) | 693.403 (sec) |
NextChar()
对我的项目来说非常重要,我需要尽可能快地完成它,我会很感激解释为什么我会得到以前的结果?
解决方案
std::ifstream
已经在做自己的内部缓冲,所以不必每次调用时都必须出去等待硬盘驱动器响应get(ch)
;99.99% 的情况下,它已经在其内部读取缓冲区中提供了您的下一个字符,并且只需复制一个字节即可将其交给您的代码。
鉴于此,将整个文件复制到您自己的单独 RAM 缓冲区中不会获得额外的加速;确实,这样做可能会使事情变慢,因为这意味着在整个文件被读入 RAM 之前,您无法开始解析数据(而使用ifstream
较小的预读缓冲区,您的代码可以尽快开始解析字符由于文件的第一部分已加载,并且解析可以在一定程度上与之后的磁盘读取并行继续)
最重要的是,每次调用它时都会按值stringstream::str()
返回一个对象,如果返回很大,这可能会非常昂贵。(即,您正在为文件内容制作一个内存副本,然后为您解析的每个字符将其丢弃!)string
string
推荐阅读
- javascript - 映射后的JavaScript数组推送-返回数组的长度?
- javascript - 连接两个数组
- shell - 查找 shell 脚本中使用的所有变量
- c++ - 为什么我不能传递对我的 unique_ptr 的引用?
- java - AWS Lambda 中线程和 java Future 接口的使用
- android - 在 firebase crashlytics 仪表板中显示的类名被混淆
- java - 找不到数学课的符号
- javascript - Svelte 应用程序错误:根据标志的值更改数组的内容失败
- deep-learning - 如何从 Google Colab 访问笔记本电脑摄像头以在实时流视频中进行对象检测?
- javascript - 在外部单击时,Ion-Input 不会失去焦点