2

我有一些写成 tag = value 的数据文件,其中 tag 是字符串,值可能是数字、字符串、数组等。我使用这种格式是因为它可读且易于编辑。现在使用这种格式实例化的每个类都有一个加载方法,它读取它需要的标签并使用这些标签中的值。我想使数据二进制以提高加载速度。一种方法是在每个类中都有一个 ToBinary(名称无关紧要)方法,该方法读取旧数据并将其写入文件,新文件用于实例化对象。这可以离线完成,仅一次/应用程序。您对此还有其他建议吗?我为此使用 C++。

编辑:我认为现在最昂贵的部分是在我第一次读取文件时解析文件,然后搜索我需要的标签,而不是从磁盘读取文件。我可以使用自定义文件系统在一个大文件中包含多个小文件。

4

6 回答 6

1

我以前没用过,但我确信Boost 的序列化模块是一个不错的起点。

于 2011-03-16T14:31:57.297 回答
1

如果您使用的是文件,那么使用二进制数据可能不会显着提高您的性能,除非您有大量数据要存储在文件中(图像、视频......)。

但无论如何,您都可以使用二进制序列化算法,例如来自Boost的算法。

于 2011-03-16T14:34:08.123 回答
1

我为此有一个序列化基类,带有带有小标题的 To/From 函数,可以嵌入版本处理。我认为对于需要在本地存储并且在大多数情况下是“只读”的简单数据来说,它是一个很好的系统。

像这样的东西:

class SeralizeMe
{
public:

 virtual bool To(Archive &file)=0;
 virtual bool From(Archive &file)=0;

 virtual bool NeedsSave(void)=0;

};

但是,如果您有以下情况,请勿使用此系统:

  • 需要经常改变格式。
  • 需要选择加载哪些数据以及存储哪些数据。
  • 使用大文件,保存时对断电特别敏感。

如果以上任何一个都适用,请使用数据库,FirebirdSQL 嵌入式是一个合适的竞争者。

于 2011-03-16T14:35:03.007 回答
0

另一个是来自 google 的 protobuf。不是最快的,但它可以支持不断发展的数据类型,并且在网络上非常高效并支持其他语言。

链接在这里

于 2011-03-16T14:34:24.663 回答
0

如果你想提高性能,你将不得不使用固定长度的字段。解析或加载可变长度字段不会显着提高性能。按文本行读取涉及扫描行尾标记。扫描浪费时间。

在使用以下任何建议之前,请分析您的代码以建立基准时间或性能数字。在每个建议之后执行此操作,因为它可以让您计算每个优化的性能增量。我的预测是每次优化后增量都会变小。

我建议首先将文件转换为固定长度的记录,仍然使用文本。根据需要用空格填充字段。因此,知道记录的大小后,您可以阻止读取到内存并将内存视为一个数组。这应该提供显着的改进。

在这一点上,您的瓶颈仍然是文件 I/O 速度,您无法真正做出重大改进(因为文件 I/O 由操作系统控制),以及扫描/转换文本。一些进一步的优化是:将文本转换为数字,最后转换为二进制。 不惜一切代价,更愿意以人类可读的形式保存数据文件。

在降低数据文件的可读性之前,请尝试将应用程序拆分为线程。一个线程处理 GUI,另一个处理输入,另一个处理处理。这个想法是让处理器总是执行你的一些代码而不是等待。在现代平台中,可以在 CPU 处理代码时执行文件 I/O。

如果您不关心可移植性,请查看您的平台是否具有 DMA 功能(DMA 或直接内存访问组件允许在不使用处理器或最小化处理器使用的情况下传输数据)。需要注意的是,许多平台在处理器和 DMA 之间共享地址和数据总线。因此,一个组件被阻塞或挂起,而另一个组件使用地址和数据总线。所以它可能有帮助,也可能没有。取决于平台的连接方式。

将 key 字段转换为使用数字,也就是tokens。由于标记是数字的,它们可以用作跳转表(也可以是 switch 语句)的索引,或者只是数组的索引。

作为最后的手段,将文件转换为二进制文件。二进制版本应该有两个字段:作为令牌的键和值。将大块数据拖入内存。

概括

  1. 将大块数据拖入内存。
  2. 在进行更改以建立基线性能测量之前进行概要分析。
  3. 一次优化一个步骤,在每次优化后进行分析。
  4. 更喜欢以人类可读的形式保存数据文件。
  5. 尽量减少对数据文件的更改。
  6. 将文件转换为使用固定长度字段。
  7. 尝试使用线程或多任务,这样应用程序就不会等待。
  8. 将文本转换为数字标记(降低人类可读性)
  9. 将数据转换为二进制作为最后的手段(人类很难阅读和调试)。
于 2011-03-16T17:43:09.907 回答
0

我有两个想法给你:

1)如果标签列表是常量并且事先已知,您可以将每个标签转换为一个字节(或字),然后是值的长度(以字节为单位),然后是值的原始 c 字符串有效载荷。

例如,给定以下内容:

Tag1 = "hello World!" // 12 bytes in length (achieved by "strlen(value) * sizeof(char)" )
Tag2 = "hello canada!"  // 13 bytes in length 

你可以把它变成字节流:

0x0001 0x000B // followed by 12 bytes representing the 'value' // 0x0002 0x000C // followed by 13 bytes representing 'value2'

您的程序只需要知道 WORD 标头“0x0001”代表 Tag1,标头“0x0002”代表 Tag2。

如果您事先不知道标签名称,您甚至可以通过遵循类似的长度、值结构进一步抽象它们。

2)也许慢一点只是您对文本解析的实现?考虑使用一个专用的开源库来完成您正在尝试做的事情。示例:“ boost::property_tree

属性树专门用于存储和检索键值对(设计用作配置设置文件)。但我想这将取决于您要存储多少这样的配对才能使这变得经济。

于 2011-03-16T19:57:58.033 回答