【问题标题】:Performance issues when reading a file from HD that dosen't follow computer byte alignments从不遵循计算机字节对齐的 HDD 读取文件时的性能问题
【发布时间】:2010-09-29 18:28:57
【问题描述】:

我有一个使用 50 字节数据结构的文件格式(.STL,立体光刻,结构是标准的,不能更改。不要与标准模板库混淆)。从HD直接读取会导致错误的数据被读取为50字节不是4的倍数。

在整个 50 字节结构中,我只需要其中的 36 个字节。我现在用来提取数据的方法是手动将文件的读取位置偏移到下一组数据开始的位置,将36个字节读取到临时变量中,然后将数据转储到临时变量中进入它在阵列上的正确位置。

这是代码块:

threePoints* output = new threePoints [numTriangles]; // create an array to hold the entire file
threePoints* temp = new threePoints [1]; // temp variable to pull data out of each "cell"

// extract each triangle individualy
for (int i = 0; i < numTriangles; i++)
{
    stlFile.seekg (96 + i * 50, ios::beg);  //read vertex data and put them into tempoary array
                                            // offset = 80 header + 4 #triangles + 12 normal vector
    stlFile.read(reinterpret_cast<char*>(temp), (36)); // read the next 36 data blocks into holder, 3 points * 3 axis * 4 bytes per float
    output[i] = temp[0]; // dump values in holder into proper array
}

此方法有效,但速度较慢。我该如何做才能使其更快、更高效?

编辑:我知道手动禁用字节对齐可以解决这个问题,但我需要大量使用生成的数组并对其进行多次迭代。我被告知禁用字节对齐会导致性能问题,因此我避免了它。

【问题讨论】:

    标签: c++ performance file-io


    【解决方案1】:

    分配一个大缓冲区(例如,足以容纳 1000 个结构)并一次读取一堆记录,而不是进行一堆小的查找和读取。 (然后遍历该缓冲区,复制出您需要的 36 字节块)。

    【讨论】:

    • 好答案。问题不是错位,问题是执行了一堆冗余的读取请求。
    • 我如何将一大块数据直接从 HD 读取到内存中,然后删除不必要的部分?我想这个问题真的不是问题,如果可能的话,更多的是我怎么做,因为我不知道。
    • 读入char 缓冲区。缓冲区中第 N 条记录的位置是 buf+(50*N),因此如果您的结构与磁盘上的对齐方式匹配,您可以说 output[i] = *(reinterpret_cast&lt;threePoints*&gt;(buf+(50*N));。如果(与其他答案一样)您不想限制对齐以匹配磁盘文件格式,请声明结构的 packedunpacked 版本并从一个复制到另一个。 (将内存中的表示与磁盘格式隔离是个好主意,因为如果您移植到不同的架构,您可以更灵活地处理字节顺序等方面的差异)
    【解决方案2】:

    #pragma pack(1,push)#pragma pack(pop) 将结构定义括起来。大多数编译器都支持这一点。则不应添加自动填充。

    GCC manual 声称它是 Microsoft 的兼容性功能,但它一直存在……可能比 GCC 本身还要长。

    【讨论】:

    • 我担心稍后迭代结构数组时的性能。我经常使用这个数组,速度很重要。上次有人告诉我禁用字节对齐会严重影响性能。
    • @Faken:另一方面,扩展数组的总大小,甚至只是复制一次也会损害性能。错位惩罚也可能非常小。我建议尝试两种方式。
    【解决方案3】:

    我没有要测试的 STL 数据,但是像这样的东西怎么样?...

    #include <fstream>
    
    #pragma pack(push, 1)
    
    struct stl_hdr {
       unsigned int header[80];
       unsigned int triangle_cnt;
    };
    
    struct triangle {
       float norm;
       float v1;
       float v2;
       float v3;
       short attr_cnt;
    };
    
    #pragma pack(pop)
    
    using namespace std;
    
    int main(int argc, char* argv[]) {
       ifstream file(argv[1], ios::in | ios::binary);
    
       if (file.is_open()) {
          stl_hdr hdr;
          file.read((char*)&hdr, sizeof(hdr));
    
          triangle* tris = new triangle[hdr.triangle_cnt];
    
          file.read((char*)tris, hdr.triangle_cnt * sizeof(triangle));
    
          file.close();
       }
    
       return 0;
    }
    

    我基于Wikipedia's description of the STL format 创建了两个结构。上面的代码与您的代码所做的假设相同……属性计数为零。我省略了错误处理/清理。

    【讨论】:

      猜你喜欢
      • 2010-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多