之前我发布了一个关于Protobuf-Net的相关但仍然不同的问题,所以这里有:
我想知道是否有人(特别是Marc)可以评论下列哪一项最有可能更快:
(a)我目前将序列化的内置数据类型存储在二进制文件中。具体来说,长(8字节)和2浮点(2x4字节)。其中每3个后来组成一个反序列化状态的对象。 long类型表示DateTimeTicks以进行查找。我使用二进制搜索来查找数据请求的开始和结束位置。然后,方法在一个块(从开始到结束位置)下载数据,知道每个块由许多上述三元组(1个长整数,1个浮点数,1个浮点数)组成,并且每个三元组总是16个字节长。因此,检索到的三元组数总是(endLocation - startLocation)/ 16。然后我遍历检索到的字节数组,反序列化(使用BitConverter)每个内置类型,然后实例化一个由三元组组成的新对象,并将对象存储在列表中以供进一步处理。
(b)执行以下操作会更快吗?构建一个单独的文件(或实现一个头),作为查找目的的索引。然后我不会存储内置类型的单个二进制版本,而是使用Protbuf-net来序列化上述对象的列表(= int的三元组,浮点数,浮点数作为对象的源)。每个List都包含完整且总是一天的数据(记住,long代表DateTimeTick)。显然,每个List的大小都会有所不同,因此我想为索引查找生成另一个文件或标题,因为每个数据读取请求只会请求整天的多天。当我想要检索一天的序列化列表时,我会简单地查找索引,读取字节数组,使用Protobuf-Net反序列化并且已经拥有我的对象列表。我想为什么我要问的是因为我不完全理解protobuf-net中的集合的反序列化是如何工作的。
为了更好地了解数据的大小,每个二进制文件大约3gb,因此包含数百万个序列化对象。每个文件包含大约1000天的数据。每个数据请求可以请求任意数量的当天数据。
您认为原始处理时间更快?我想在可能编写大量代码来实现之前获取一些输入(b),我目前有(a)并且能够在我的机器上每秒处理大约150万个对象(进程=从数据请求到返回的反序列化列表对象)。
总结:我问的是二进制数据是否可以更快地读取I / O并使用方法(a)或(b)进行反序列化。
答案 0 :(得分:5)
我目前将序列化的内置数据类型存储在二进制文件中。具体来说,长(8字节)和2浮点(2x4字节)。
你拥有的是一些非常简单的数据(而且没有违法行为)。如果你对处理原始数据感到满意(听起来就像你这样),那么对我而言,最好的方法就是:就像你一样。偏移量是16等的干净倍数
协议缓冲区(不仅仅是protobuf-net,它是protobuf规范的单个实现),适用于更复杂的场景:
这是一个不同的用例!作为其中的一部分,协议缓冲区使用一个小但必要的字段标头符号(通常每个字段一个字节),你需要一种机制来分隔记录,因为它们不是固定大小 - 通常是每个2字节记录。并且,最终,协议缓冲区处理浮点数是IEEE-754,因此您将存储完全相同的 2 x 4字节,但添加了填充。在协议缓冲区规范中,长整数的处理可以是固定的或可变大小。
对于你正在做的事情,因为你关心最快的原始处理时间,简单似乎最好。我会“按原样”离开。
答案 1 :(得分:1)
我认为每天使用一个“块”和一个索引是一个好主意,因为只要每个记录是16字节固定大小,它就会让你进行随机访问。如果您有一个索引跟踪文件中每天的偏移量,您还可以使用memory mapped files创建特定日期或天数的非常快速的数据视图。
协议缓冲区的一个好处是它们使固定大小的数据变量大小,因为它压缩值(例如,使用一个字节写入长值为零)。这可能会为您提供大量数据随机访问的一些问题。
我不是protobuf专家(我觉得Marc会在这里填写你的信息)但我的感觉是Protocol Buffers真的最适合作为一个整体访问的中小批量的非平凡结构化数据(或者至少在整个记录中)。对于非常大的随机访问数据流,我认为不会有性能提升,因为当不同的记录可能被不同的量压缩时,您可能会失去进行简单随机访问的能力。