繁体   English   中英

解析mmap()版本的文件

[英]parsing a mmap()-ed file

通过mmap-ed文件解析的最佳(最快)方法是什么? 它包含成对的数据(字符串int),但是我不能认为它们之间有一定数量的空格/制表符/换行符。

假设您已经映射了整个文件(而不是大块的文件,因为那样会使生活变得非常复杂),我将执行以下操作...

// Effectively this wraps the mmaped block
std::istringstream str;
str.rdbuf()->pubsetbuf(<pointer to start of mmaped block>, <size of mmaped block>);

std::string sv;
std::string iv;

while(str >> sv >> iv)
{
  // do stuff...
}

我认为应该可以...

警告这是实现定义的行为,请参见此答案以获取更好的方法。

如果最好/最快的意思是最容易编写代码,那么这是不推荐使用的std::istrstream适合的罕见情况之一; 调用istrstream::istrstream(char const*, std::streamsize)构造函数重载,然后像从其他任何std::istream一样从流中提取数据。 (这不会像std::istringstream那样复制底层内存。)

如果以最佳/最快的速度表示最佳/最快的运行时性能,我认为您将无法击败boost 精神 qi或手写解析器,尽管我认为前者更容易编写和维护(如果您以前从未使用过boost.spirit,则可以忽略图书馆学习曲线)。

解析由空格分隔的字符串/整数对(即foo 50 bar 20 baz 123)应该快如闪电。 到目前为止,更重要的因素是
a)页面实际上在RAM中,仅mmap不能保证
b)缓存行在L1缓存中

默认情况下,虽然mmap在顺序访问中确实已预先读取,但磁盘访问的时间为数十毫秒 ,而对4k页内存的解析(理想情况下)为数十微秒。
因此,您不能指望预取器能够跟上步伐,特别是因为它只会在看起来您需要更多时才进行预取(即使假设查找时间为零,由于机械磁盘上​​的旋转延迟,它实际上也保证了前期成本)。
因此,除非您的总数据只有十几个千字节(在这种情况下,无论如何,如何尽可能快地处理它都是毫无意义的),在开始扫描之前先疯狂(MADV_WILLNEED)是有意义的,因此系统不会等着看您的访问模式触发它的启发式方法,而是顺序地读取它可以不间断地读取的内容。 一旦超过访问时间,磁盘带宽(顺序)就很大。 您可能仍然会追上来,但要晚得多。 如果您的数据集足够大,因此可能不适合放入RAM,则对时不时看到的数据调用MADV_DONTNEED是一个好主意。

对于页面错误,也适用于高速缓存未命中。 缓存的负载为1-2个周期,内存的负载为200-500个周期。
CPU具有针对顺序访问模式的自动预取功能,但是受到限制。
首先,预取永远不会跨越页面边界。 那是因为如果是这种情况,那么自动预取将有规律地触发页面错误,这将是非常不愉快的。
其次,仅在连续两次未命中之后才进行预取,这是为了确保仅在可能有意义的情况下才启动预取。 为每个随机读取预取相邻的缓存行将是愚蠢的,因为这会不必要地浪费宝贵的缓存行。
第三,预取需要时间,一旦CPU中的启发式触发器触发,您就已经在争夺数据,因此,早于晚。
幸运的是, 您知道将需要什么数据,并且知道很长时间了。 因此,您可以给出预取提示,这将为CPU提供宝贵的开始时间(例如,预取半个千字节)。

就目前而言,您的问题太含糊而无法回答。

不过,如果你需要做的是让一些数据出来的文件,你不想做的是使用将在修改内存的方法mmap编辑区域。

编辑现在,您已经编辑了问题,这更加清楚了。 作为起点,我将使用单个char指针来遍历整个mmap ed文件。 提取字符串非常简单(确切的方法取决于您需要对结果执行什么操作),并且可以使用atoi等人提取整数。

您可以通过std::string访问它,并使用std::istringstream以便顺序读取它。 或者使用一些更方便的库,例如,在Qt中,您可以在从映射的内存构造的QByteArray上使用QTextStream

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM