较大数据文件的读取优化过程续

来源:互联网 发布:apache ignite 编辑:程序博客网 时间:2024/05/17 22:54

由来

在上一篇博客(见参考1)中写了从基本到优化的过程,但仍然有可以优化的余地,这里记录下。

问题

文章1中根据固定行字节数优化读取速度有很大的弊端,就是需要解析的文件可能是不规则行长度的。可以有通用的按行解析的方法。当然前提仍然是基于内存映射文件。这里操作一个dat文件,共分n段,数据以空格分隔,行以\r\n分隔,大部分段平均每行大约10个双精度浮点数,小部分整数。共180w行,300MB大小。

char*+sscanf方法

首先想到的是c的速度快,直接操作指针应该速度不错。
那么主要方法就是查找换行符,和前一个换行符组成当前行字符串,再用sscanf分解到double d[10]数组里去。
结果是:release下19S读完。

char*+strtok_s方法

继续优化,sscanfsscanf_s 都是可变参数函数模板,一定效率比较低,换成 strtok_s
主要方法是先查找换行符,和前一个换行符组成当前行字符串,再用strtok_s分隔行字符串到double d[10]数组里去。
结果是:release下16S读完。

stdstring+strtok_s方法

继续优化,上面的设想都是认为c肯定比c++快,但真的这样吗?尝试的态度下用了string做行分隔,结果却证明这种情况下stringchar*快。
主要方法是得到内存映射文件指针后,直接用这个指针构造string长字符串,然后对这个字符串用find('\n')来分隔行,再按上面的方法用strtok_s分隔具体的数组。
结果是:release下7.9s读完。很大的提升了,可见思维定势不能有啊,c++一样可以快。

多线程 +stdstring+strtok_s方法

还能继续优化吗?
从上面的方法可以看到,一开始整个文件已经转为字符串在内存里了,虽然不能用多线程直接读文件,但用多线程读内存是可以的!
主要方法是这样:先遍历一遍全部字符串,找出每段开头的偏移量,记录下来,然后开线程,在线程函数里,传入这个偏移量,解析即可。
结果是:4.4s读完。
注意:开线程的数量应该是有讲究的,我是选择和cpu线程数相同,不同的时候经过测试,不如相同

继续优化?

还能继续优化吗?或许c++17并行库可以

参考文献

1.较大数据文件的读取优化过程

0 0