啜饮或吞咽文件



我有一系列文本文件,我想读取这些文件作为有限状态机的输入。因此,一次只需要该文件中的一个字符。现在,据我所知,内存访问是一项耗时的操作,导致了这个问题:

在使用数据之前,将整个(小到中等大小的)文件加载到内存中是否更快,或者ifstream是否经过了足够的优化,以至于重复插入硬盘不会影响性能?

如果你知道文件大小很小,你可以一次读取所有文件,如果文件很大,那么最好一次读取一行。现在,对于存储您所读取的内容,这可能取决于您正在读取的数据类型以及您如何打开文件(文本或二进制)。如果你用二进制打开,你可以把它们存储到unsigned char*中,但你必须知道你的数据结构包含多少字节,这取决于预期的数据类型。如果您正在读取文本文件,则可以将内容保存到字符串中,但如果将其保存到字符串,则需要相应地解析字符串。打开和关闭文件往往比在内存中工作要慢。当你从硬盘访问文件时,你使用的总线往往较慢,而且你可能会有缓存未命中。在ram中工作通常更快。

表示这一点的一种简单方法是将3D对象渲染到CPU上的屏幕与将批量数据集发送到GPU进行比较。想象一个3D图形引擎,它存储一批顶点信息,其中每个顶点可能包含以下信息;(x,y,z)世界位置,(x,y)具有(r,g,b,a)颜色信息的屏幕像素信息,正常&用于光处理的切线矢量信息和用于纹理坐标信息的(t,s)或(u,v)。因此,一个简单的三角形可能看起来像这样:

// These Structs I Have Put Into Columns To Preserve Page Length   
//  8 Bytes                  16 Bytes               8 Bytes
struct Vec2f {           struct Vec2d {          struct Vec2i {
    union {                  union {                 union {
         float f2[2];            double d2[2];           int i2[2];
         // Positional
         struct {                struct {                struct {
             float x;                double x;               int x;
             float y;                double y;               int y;
         };                      };                      };
         // Texture Coords - Some Use S&T Others Use U&V
         struct {                struct {                struct {
             float s;                double s;               int s;
             float t;                double t;               int t;
         };                      };                      };
         /*struct {                struct {                struct {
             float u;                double u;               int u;
             float v;                double v;               int v;
         }; // Only Shown Here   };                      };*/
         // Color Values.
         struct {                struct {                struct {
             float r;                double r;               int r;
             float g;                double g;               int g;
         };                      };                      };
    };                       };                      };
};                       };                      };
//  12 Bytes                24 Bytes               12 Bytes
struct Vec3f {           struct Vec3d {          struct Vec3i {
    union {                  union {                 union {
         float f3[3];            double d3[3];           int i3[3];
         struct {                struct {                struct {
             float x;                double x;               int x;
             float y;                double y;               int y;
             float z;                double z;               int z;
         };                      };                      };
         struct {                struct {                struct {
             float s;                double s;               int s;
             float t;                double t;               int t;
             float p;                double p;               int p;
         };                      };                      };
         struct {                struct {                struct {
             float r;                double r;               int r;
             float g;                double g;               int g;
             float b;                double b;               int b;
         };                      };                      };
    };                       };                      };
};                       };                      };
//  16 Bytes                  32 Bytes               16 Bytes
struct Vec4f {           struct Vec4d {          struct Vec4i {
    union {                  union {                 union {
         float f4[4];            double d4[4];           int i4[4];
         struct {                struct {                struct {
             float x;                double x;               int x;
             float y;                double y;               int y;
             float z;                double z;               int z;
             float w;                double w;               int w;
         };                      };                      };
         struct {                struct {                struct {
             float s;                double s;               int s;
             float t;                double t;               int t;
             float p;                double p;               int p;
             float q;                double q;               int q;
         };                      };                      };
         struct {                struct {                struct {
             float r;                double r;               int r;
             float g;                double g;               int g;
             float b;                double b;               int b;
             float a;                double a;               int a;
         };                      };                      };
    };                       };                      };
};                       };                      };
// Not All Triangles Sent To Be Rendered To The Screen Will Have All Of This
// Information, But There Is A Good Chance That Many Will.
struct TriangleMeshF {
    // If We Do The Math For This One Triangle Mesh
    // The Float Vecs Are 8, 12 & 16 Bytes Each
    Vec3f v3Vertices[3]; // 3 Vertexes That Make This Triangle
    Vec4f v4Color[3];    // 3 Colors 1 For Each Vertex
    Vec2f v2TexCoord[3]; // 3 Texture Coords 1 For Each Vertex
    Vec3f v3Normal[3];   // 3 Normal Vectors 1 For Each Vertex
    Vec3f v3BiNormal[3]; 
    Vec3f v3Tangent[3];
    Vec3f v3BiTangent[3];
    // 12*3*5 + 16*3 + 8*3 = 252 Bytes  Or There are 63 4Byte Floats
}; 
// 252 Bytes Doesn't Seem Like A Large Amount Of Data But What Happens When 
// We Have A Model File That Fills In A vector<TrianleMesheF>
// Lets Say That This One Model File Fills This vector<T> with 80K TriangleMeshes
// The Amount Of Data Being Processed On The CPU Is Slower Than The GPU
// Also The Amount Of Rendering Calls From The CPU To The GPU Can Be Slow
// Because It Travels Over The Bus. This Is Why 3D Graphis Engine Developers
// Who Use Either DirectX Or OpenGL OR Both Use Batches To Collect Buckets
// Of Different Types Of Rendering Meshes Then Sends Them To The Graphics
// Card When The Buckets Become Full. This Is Kind Of How The Process
// Or Concept Of Programmable Shaders Came Into Play
// I Only Used Vec2f, 3f, & 4f Here, But Imagine If The User Had Used Vec4d
// Then The Mesh Would Double In Size And This Would Get Large Very Fast.

这似乎有点偏离主题,但这里的概念仍然适用。当您使用处理器通过总线与视频卡、声卡、硬盘驱动器、光盘驱动器、网络等进行通信时,这是一个比直接从ram工作更慢的过程,就像传统的OS-CPU ram比GPU-ram慢一样。

因此,这一切都取决于你的数据类型,你如何以文本或二进制形式读取文件,以及文件大小有多大。正如我之前所说,两种最常见的方法要么是一次性将文件读取到缓冲区结构中,要么是逐行将其内容保存到无符号字符数组、字符数组或字符串中。如果它都是纯数字,那么它可能是一个int数组。这对于float或doubles不起作用,因为您必须为此解析文本。

正如您所说,您使用的是txt文件,因此最好的选择很可能是,如果文件大小小于您设置的特定文件大小限制,那么很容易打开文件并逐行读取。如果它比这个大,但比太大小,你可以一口气读完。如果它太大,无法容纳可用的内存量,或者太大,不能容纳在单个缓冲区中,那么你有几个选项,你可以设置一个缓冲区大小,比如4MB或2GB,当你读取文件并将其保存到缓冲区时,你必须计算你已经读取了多少,然后一旦达到最大缓冲区大小时,你就必须存储第一个缓冲区,然后创建一个新的缓冲区并继续读取并重复此操作,直到达到EOF。逐行阅读也可以,这在阅读过程后会更好一些。逐行使解析文本字符串变得更加容易。与必须将此缓冲区分隔成文本行相反。

然而,要做到这一点,您必须有两到三个不同的解析机制。一个用于读取所有内容,另一个用于逐行读取并确定何时执行哪个操作。它可能只需要一些额外的函数或方法,但您可能想要解析整个读取,寻找换行符'/0',然后将其保存到字符串中,并将该字符串推送到向量中。然后将这个向量传递给解析器,以查找关键字或令牌。一行一行可以直接保存到向量容器中。在确定文件大小限制时,您需要知道在readAll()和readLine()之间切换,您可能需要进行基准速度测试来确定合适的文件大小。我希望这能帮助你做决定。

只要有足够的RAM,一次读取整个文件通常会更快。ifstream是缓冲的,但(1)只有你才能知道缓冲区的最佳大小,(2)也有一些开销(与此相比)。

相关内容

  • 没有找到相关文章

最新更新