加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c有效地读取每个X字节中的前几个字节

发布时间:2020-12-16 10:13:15 所属栏目:百科 来源:网络整理
导读:我想读取文件的每个X * 16字节中的前16个字节.我编写的代码可以工作,但由于函数调用很多,所以代码很慢. std::vectorVertex readFile(int maxVertexCount) { std::ifstream in = std::ifstream(fileName,std::ios::binary); in.seekg(0,in.end); int fileLeng
我想读取文件的每个X * 16字节中的前16个字节.我编写的代码可以工作,但由于函数调用很多,所以代码很慢.

std::vector<Vertex> readFile(int maxVertexCount) {
    std::ifstream in = std::ifstream(fileName,std::ios::binary);
    in.seekg(0,in.end);
    int fileLength = in.tellg();
    int vertexCount = fileLength / 16;

    int stepSize = std::max(1,vertexCount / maxVertexCount);

    std::vector<Vertex> vertices;
    vertices.reserve(vertexCount / stepSize);
    for (int i = 0; i < vertexCount; i += stepSize) {
        in.seekg(i * 16,in.beg);
        char bytes[16];
        in.read(bytes,16);
        vertices.push_back(Vertex(bytes));
    }
    in.close();
}

有人可以给我一些建议来提高这段代码的性能吗?

解决方法

它可能不是函数调用本身,而是非顺序访问模式,从大文件中选取小段.即使您只读取16个字节,存储子系统也可能会读取(并缓存)较大的块.您的访问模式对于典型的I / O是致命的.

(分析应该显示磁盘访问是否是瓶颈.如果是“许多函数调用”,CPU将是.)

那么,首先,你能改变这个要求吗?
这在所有情况下都是最简单的方法.

你能少分散吗?例如.而不是读取顶点0,20,40,…,1000,读取顶点0,1,2,3,4,100,101,102,103,104,200,201,202,203,204,… – 来自文件“所有部分”的相同数量的顶点.

第二,特定于操作系统的优化.
没有可移植的方法来控制操作系统级别的缓存.

一种解决方案是内存映射文件(Windows上的CreaterFileMapping,Linuxy系统上的mmap),如@Nim所建议的那样.这可以省略一个内存副本,但仍会读取整个文件.

对Linux无能为力,但在Windows上你有CreateFile的参数:

> FILE_FLAG_NO_BUFFERING这基本上意味着你进行缓冲,让你更好地控制发生的缓存,但你不能无所畏惧地寻求阅读.
> FILE_FLAG_SEQUENTIAL_SCAN,它只是缓存不存储旧数据的缓存

这些都不会解决您的访问模式的问题,但第一个可能会稍微调整它 – 特别是如果您的步骤大于磁盘扇区,第二个可以从子系统承受压力.

第三,快照.
最佳选择可以是将交错快照存储在关联文件中.

对于特定的maxVertexCount,快照可能只是您操作的结果.或多个快照,如mipmapping.想法是通过顺序读取来替换分散的读取.

或者,快照可以以交错顺序存储数据.对于128个顶点,您可以按顺序存储顶点(粗略地,要注意off-by< -one,零vs-one-based和别名效果,以及我的错误): 64,32,96,16,48,80,112 8,24,56,72,88,120 …… 无论您是读取前3个或前7个或前15个还是前31个…值,样本都会在文件中均匀分布,就像您的原始代码一样.将它们重新排列在内存中会快得多 – 特别是如果它只是一小部分. 注意:您需要一个强大的算法来检测您的快照是否过时,而不管在不同文件系统上“最后写入日期”发生的许多有趣的事情.主文件中的“更改计数器”将是最安全的(尽管它会增加更改的成本). 第四,更改文件格式 (如果你可以控制那个)
上面建议的交错存储可以用于整个文件.但是,这对处理有很大影响 – 特别是如果您需要在某个时刻恢复“原始”订单.

优雅的选项是将这样的交错子集作为文件的一部分,以及原始顺序的完整顶点列表.有一个cutoff stepSize,这对此不再有太大帮助,可能是磁盘的2 *扇区/块大小.因此文件大小只会增加几个百分点.但是,写入会花费更多,顶点数量的变化会更加严重.

别名警告

如果这是为了获得“统计”或“视觉上足够”的采样,固定的stepSize可能会有问题,因为它可以创建数据中存在的任何模式的混叠效果(想想莫尔模式).

在这种情况下,随机抽样将是可取的.这可能听起来很可怕并使一些解决方案更难以实现,但通常是避免许多次优案例的最简单方法.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读