C++ 使用更平坦模式的性能影响
我使用FlatBuffers(C++)来存储关于文件的元数据信息。这包括EXIF、IPTC、GPS和各种其他元数据值 在我当前的模式中,我有一个相当规范化的定义,上面列出的每个组都有自己的表。根表只包含每个子表的属性 基本示例:C++ 使用更平坦模式的性能影响,c++,flatbuffers,C++,Flatbuffers,我使用FlatBuffers(C++)来存储关于文件的元数据信息。这包括EXIF、IPTC、GPS和各种其他元数据值 在我当前的模式中,我有一个相当规范化的定义,上面列出的每个组都有自己的表。根表只包含每个子表的属性 基本示例: table GPSProperties { latitude:double; longitude:double; } table ContactProperties { name:string; email:string; } table EXIFP
table GPSProperties {
latitude:double;
longitude:double;
}
table ContactProperties {
name:string;
email:string;
}
table EXIFProperties {
camera:string;
lens:string;
gps:GPSProperties;
}
table IPTCProperties {
city:string;
country:string;
contact:ContactProperties;
}
table Registry {
exifProperties:EXIFProperties;
iptcProperties:IPTCProperties;
}
root_type Registry;
这是可行的,但构建缓冲区时的嵌套限制开始使代码变得非常混乱。同样,将属性拆分为单独的表只是为了模式的清晰性
我正在考虑将整个模式“展平”到一个表中,但我想知道这样做是否会影响性能或内存。这个表可能有几百个字段,但大多数字段都是空的
提议:
table Registry {
exif_camera:string;
exif_lens:string;
exif_gps_latitude:double;
exif_gps_longitude:double;
iptc_city:string;
iptc_country:string;
iptc_contact_name:string;
iptc_contact_email:string;
}
root_type Registry;
由于未设置或设置为默认值的属性不会占用任何内存,因此我倾向于认为扁平化模式可能不是问题。但我不确定
(请注意,性能是我最关心的问题,紧随其后的是内存使用情况。规范化模式的性能非常好,但我认为扁平化模式确实可以帮助我清理代码库。)基本知识您应该首先了解:
因此,这取决于您的数据是否将是巨大的和异构的,请使用更有组织的层次结构。但是,如果您的数据是同质的,那么您更喜欢扁平的表。因为您的大多数数据都是字符串,所以这两种设计的大小和速度都非常相似,因此您可能应该从软件工程的角度来选择对您更有利的设计 这就是说,平面版本可能会在大小上稍有效率(vtables更少),而且访问速度肯定会更快(不过,考虑到它主要是字符串数据,这也是微不足道的) 平面版本效率较低的唯一方法是将大量数据存储在一个缓冲区中,每个表之间设置的字段差异很大。然后,非平面版本可能会生成更多vtable共享 在非平面版本中,如果字段不太可能更改,则像
gpsprroperties
这样的表可以是struct
,这样会更有效
这个表可以有几百个字段,但大多数字段都可以
空着
性能成本可能很小,你不会注意到,但你上面的报价,对我来说,是影响使用哪种设计的因素
当其他人谈论vtables的成本时;我一点也不担心。每个类只有一个vtable,每次运行准备一次,不会太贵。
但是,拥有100个空字符串和未使用的字符串将非常昂贵(内存使用方面),并且会消耗您创建的每个对象;此外,读取字段将变得更加复杂,因为您不能再假设在读取时类的所有数据都在那里
如果大部分/所有的领域都在那里,那么我可以看到制作一门课程的吸引力;但事实并非如此。我创建的每个缓冲区都代表一个文件,每个缓冲区都独立地存储在一个数据库条目中,因此我认为不会有任何“共享”。在我提出的“平面模式”中,最终缓冲区中只有一个“注册表”对象,因此我认为我不会从任何v表共享中受益。我做了一些快速测试,创建了一个包含300个
int
类型字段的表,并随机设置了少量字段。在这样一个基本的测试中,情况似乎“正常”。(即:内存使用量与我预期的差不多,但可能300的质量不如“许多字段”。)如上文所述,每个缓冲区与任何其他缓冲区分开存储,因为它代表单个文件的元数据。我在上面使用了图像元数据,但也可能有用于PDF、音频、视频、文件系统、XMP等元数据的字段。肯定超过100,但不超过“几百”。大多数都是空的,因为它们依赖于文件类型。(即:图像fie将填充EXIF和IPCT相关字段,但保留所有其他字段的默认值。)缓冲区将只有一个表作为其根,数据将存储在SQLite列中。啊,我没有得到100多个字段。如果未与其他对象共享,则每个未使用字段的开销为2字节。只有在使用/未使用的结构与其他表重叠的情况下,非平面版本才能节省这一成本。如果您的数据是超稀疏的,您是否考虑过联合向量?老实说,如果上面提到的对于超稀疏数据来说效率仍然很低,那么协议缓冲区处理超稀疏数据的效果会更好。。。我错过了那个小细节,我的测试没有抓住它,因为我总是在构造函数中设置一个以上的参数后检查缓冲区的大小。设置第1个和第100个字段会产生更大的缓冲区。我认为教程中的这行是:“……这也意味着,您不必担心只在少量实例中添加很多字段,因为如果未使用,它不会膨胀缓冲区。”应该有点澄清。FlatBuffer没有被存档到相应的C++类中。相反,FlatBuffer只是用于存储。当我需要metada的值时