1

我之前发布了一个关于 Protobuf-Net 的相关但仍然不同的问题,所以这里是:

我想知道是否有人(尤其是 Marc)可以评论以下哪项最有可能更快:

(a) 我目前将序列化的内置数据类型存储在二进制文件中。具体来说,一个 long(8 个字节)和 2 个浮点数(2x 4 个字节)。之后的每 3 个组成一个处于反序列化状态的对象。long 类型表示 DateTimeTicks 用于查找目的。我使用二进制搜索来查找数据请求的开始和结束位置。然后,一种方法将数据下载到一个块中(从开始到结束位置),知道每个块由许多上述三元组(1 个长,1 个浮点数,1 个浮点数)组成的数据包,并且每个三元组总是 16 个字节长。因此,检索到的三元组数始终为 (endLocation - startLocation)/16。然后我遍历检索到的字节数组,反序列化(使用 BitConverter)每个内置类型,然后实例化一个由三元组组成的新对象,并将对象存储在列表中以供进一步处理。

(b) 执行以下操作会更快吗?构建一个单独的文件(或实现一个标头),用作查找目的的索引。然后我不会存储内置类型的单个二进制版本,而是使用 Protbuf-net 序列化上述对象的列表(= int、float、float 的三元组作为对象的源)。每个 List 将包含准确且始终为一天的数据(请记住,long 表示 DateTimeTick)。显然,每个列表的大小都会有所不同,因此我的想法是生成另一个文件或标题以用于索引查找,因为每个数据读取请求只会请求一整天的倍数。当我想检索一天的序列化列表时,我会简单地查找索引,读取字节数组,使用 Protobuf-Net 反序列化并且已经有了我的对象列表。

为了更好地了解数据的大小,每个二进制文件大约 3gb 大,因此包含数百万个序列化对象。每个文件包含大约 1000 天的数据。每个数据请求都可以请求任意天数的数据。

您认为原始处理时间更快的是什么?我想在可能编写大量代码来实现(b)之前获得一些输入,我目前有(a)并且能够在我的机器上每秒处理大约 150 万个对象(处理 = 从数据请求到返回的反序列化列表对象)。

摘要:我在问二进制数据是否可以使用方法(a)或(b)更快地读取 I/O 和反序列化。

4

2 回答 2

5

我目前将序列化的内置数据类型存储在二进制文件中。具体来说,一个 long(8 个字节)和 2 个浮点数(2x 4 个字节)。

你所拥有的是(无意冒犯)一些非常简单的数据。如果您对处理原始数据感到高兴(听起来您很高兴),那么在我看来,处理此问题的最佳方法是:照您的样子。偏移量是 16 的一个很好的干净倍数,等等。

通常,协议缓冲区(不仅仅是 protobuf-net,它是 protobuf 规范的单一实现)旨在用于一组更复杂的场景:

  • 嵌套/结构化数据(想想:xml 即复杂记录,而不是 csv 即简单记录)
  • 可选字段(某些数据可能根本不存在于数据中)
  • 可扩展/版本容错(可能存在意外或仅半预期的值)
    • 特别是,可以添加/弃用字段而不会破坏
  • 跨平台/基于模式
  • 并且最终用户不需要参与任何序列化细节

这是一个不同的用例!作为其中的一部分,协议缓冲区使用一个小但必要的字段标题符号(通常每个字段一个字节),并且您需要一种机制来分隔记录,因为它们不是固定大小的 - 通常每个另外 2 个字节记录。而且,最终,float 的协议缓冲区处理是 IEEE-754,因此您将存储完全相同的2 x 4 字节,但添加了填充。在协议缓冲区规范中,长整数的处理可以是固定大小或可变大小。

对于您正在做的事情,并且由于您关心最快的原始处理时间,简单似乎是最好的。我会保持“原样”。

于 2012-06-19T08:25:43.600 回答
1

我认为每天使用一个“块”和一个索引是一个好主意,因为只要每条记录是 16 字节固定大小,它就可以让你进行随机访问。如果您有一个索引来跟踪文件中每天的偏移量,您还可以使用内存映射文件来创建特定日期或日期范围内数据的非常快速的视图。

协议缓冲区的好处之一是它们使固定大小的数据可变大小,因为它压缩了值(例如,使用一个字节写入零的长值)。这可能会给您在大量数据中的随机访问带来一些问题。

我不是 protobuf 专家(我觉得 Marc 会在这里填补你的空白),但我的感觉是 Protocol Buffers 真的最适合作为一个整体访问的中小型非平凡结构化数据量(或至少在全部记录)。对于非常大的随机访问数据流,我认为不会有性能提升,因为当不同的记录可能被不同的数量压缩时,您可能会失去进行简单随机访问的能力。

于 2012-06-19T08:19:56.713 回答