C++ c++;有效读取每个X字节中的前几个字节

C++ c++;有效读取每个X字节中的前几个字节,c++,windows,performance,file,bytebuffer,C++,Windows,Performance,File,Bytebuffer,我想从文件的每个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 vertexCoun

我想从文件的每个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();
}
std::向量读取文件(int-maxVertexCount){
std::ifstream in=std::ifstream(文件名,std::ios::binary);
in.seekg(0,in.end);
int fileLength=in.tellg();
int vertexCount=fileLength/16;
int stepSize=std::max(1,vertexCount/maxVertexCount);
向量顶点;
顶点保留(顶点计数/步长);
对于(int i=0;i

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

不要使用
seek
,我会
mmap
整个文件,然后简单地读取所需位置的字节

我不打算为您编写代码,但应该遵循以下原则:

  • 打开文件,计算文件大小
  • mmap
    整个文件
  • 迭代步长,计算每个块的地址
  • 基于块构造每个
    顶点
    ,并推入向量
  • 返回向量

  • 。。。如果由于某种原因您不能使用
    映射
    ,请“大口”将文件读入缓冲区。。。缓冲区大小是
    X
    字节的倍数。继续读取该缓冲区(注意读取了多少字节)。直到到达文件的末尾

    您特别想要避免的是一大堆物理I/O操作:磁盘读/写机制的移动。由于这个原因,操作系统喜欢缓冲东西,但它只能猜测应用程序正在尝试做什么,而且可能猜错了。一旦磁盘将读/写磁头定位到正确的磁道(“寻道时间”),它可以在一次旋转中检索整个磁道的数据。但“寻找时间”相对较慢


    映射文件,然后非随机地读取映射文件中的数据,显然是最有利的策略,因为现在操作系统确切地知道发生了什么。

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

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

    因此,首先,您可以更改此要求吗?
    这在所有情况下都是最简单的解决方法

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

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

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

    Linux帮不了什么忙,但在Windows上,您可以使用以下参数来创建文件:

    • FILE\u FLAG\u NO\u BUFFERING
      这基本上意味着你做了缓冲,让你更好地控制发生的缓存,但你不能随意地查找+读取

    • FILE\u FLAG\u SEQUENTIAL\u SCAN
      只需telsl缓存,不存储旧数据

    这两种方法都不能解决访问模式的问题,但第一种方法可能会在某种程度上解决这个问题,特别是当您的步骤大于磁盘扇区时,第二种方法可能会承受子系统的压力

    第三,快照。
    最好的选择可能是将交错快照存储在相关文件中

    对于特定的
    maxVertexCount
    ,快照可能只是您操作的结果。或多个快照,如mipmapping。其思想是用顺序读取代替分散读取


    或者,快照可以交错顺序存储数据。对于128个顶点,您可以按该顺序存储顶点(大致上,注意off by首先,我假设您正在从定义中按值返回向量,即使您发布的代码缺少return语句,因此必须复制向量。通过引用将其传递到方法中,因此不需要复制

    您可以使用低级别来阅读,而无需查找:

    void readFile( size_t maxVertexCount, std::vector<Vertex> &vertices )
    {
        struct stat sb;
        int fd = std::open( fileName, O_RDONLY );
        std::fstat( fd, &sb );
    
        size_t vertexCount = sb.st_size / 16;
    
        size_t stepSize = std::max( 1, vertexCount / maxVertexCount );
    
        vertices.reserve( vertexCount / stepSize );
    
        for ( off_t i = 0; i < vertexCount; i += stepSize)
        {
            char bytes[ 16 ];
            std::pread( fd, bytes, 16, 16 * i );
            vertices.push_back( Vertex( bytes ) );
        }
    
        std::close( fd );
    }
    
    void readFile(大小\u t maxVertexCount,标准::向量和顶点)
    {
    结构统计某人;
    int fd=std::open(仅文件名);
    标准:fstat(fd和sb);
    尺寸垂直计算=sb.st\U尺寸/16;
    大小\u t步长=标准::最大值(1,vertexCount/maxVertexCount);
    顶点保留(顶点计数/步长);
    对于(off_t i=0;i
    您应该能够找出所需的错误处理和头文件


    这将利用内核的页面缓存和可能的预读
    或读取整个文件的速度可能更快,也可能不会更快。

    谢谢您的回复。这似乎是更好的解决方案,因为由于windows的原因,mine.mmap不是一个选项。我尝试使用ifstream来读取整个文件,但第二步会变慢(整个文件可能高达1 TB)。嗯,您没有真正指定约束条件……无论如何,