我有一种奇怪的情况发生,我不太了解 .
我有一个'数据集'类,其中包含有关监视浮标的各种元数据,包括“传感器”列表 .
每个电流'sensorstate' .
每个'sensorstate'都有一些关于它的元数据(时间戳,更改原因等),但最重要的是它有一个 Dictionary<DateTime,float>
的值 .
这些传感器通常具有超过50k的数据点(相当于15分钟的数据读数),所以我想找到一些比默认的.NET BinaryFormatter
更快的序列化的东西,因此设置Protobuf-net将会非常快速地序列化 .
不幸的是,我的问题发生在反序列化时,我的值字典引发了一个异常,因为已经有一个项目添加了相同的键,并且我可以让它反序列化的唯一方法是启用'OverwriteList'但我有点不确定为什么当序列化时没有任何重复的键(它是字典),那么为什么在反序列化时会出现重复的键?这也带来了数据完整性问题 .
任何帮助解释这一点将非常感激 .
(另一方面,当给出ProtoMember属性id时,它们是否需要对类或整个项目是唯一的?我正在寻找与protobuf-net结合使用的无损压缩建议,因为文件变得非常大)
编辑:
我刚刚将我的源码放在GitHub上,这是有问题的类
SensorState(注意:它目前有OverwriteList = true以使其适用于其他开发)
这是一个例子raw data file
我已经尝试过使用SkipContructor标志,但即使将其设置为true,它也会获得异常,除非对于值字典,OverwriteList也是如此 .
2 回答
如果
OverwriteList
修复它,那么它告诉我字典默认有一些数据,可能是通过构造函数或类似的 . 如果它确实来自构造函数,则可以使用[ProtoContract(SkipConstructor=true)]
禁用它 .如果我误解了上述内容,如果可能的话,可以通过可重复的示例进行说明 .
关于id,它们只需要在每种类型中都是唯一的,并且建议保持它们小(由于标签的“varint”编码,小键比大键“更便宜”) .
如果你想真正减小尺寸,我实际上也会建议查看数据的内容 . 例如,你说这是15分钟的读数......好吧,我猜有偶尔的差距,但你可以做,例如:
并为每个连续的15分钟值组成一个
Block
(这里的假设是每个值在最后一个之后为15,否则启动一个新块) . 因此,您要存储多个Block
实例来代替单个字典 . 这有以下优点:要少得多
DateTime
值存储你可以在浮点数上使用"packed"编码,这意味着它不需要添加所有中间标记;你通过将数组/列表标记为(
[ProtoMember({key}, IsPacked = true)]
)来做到这一点 - 注意它只适用于一些基本数据类型(不是子对象)综合起来,这两个调整可以带来显着的节省
如果数据有很多字符串,你可以尝试GZIP / DEFLATE . 您当然可以尝试这两种方式,但是如果没有大量的字符串数据,我会谨慎地期望从压缩中获得额外的额外费用 .
作为基于提供的(CSV)数据文件的更新,处理字典没有固有的问题 - 如图所示:
这是我道歉的地方,因为它曾暗示它与我自己没有做的代码有任何关系 . 虽然我在这里疯狂支持protobuf和Marc Gravell背后的团队为protobuf-net而且非常快 .
发生的事情是在Sensor类中我有一些逻辑,永远不会让一些属性永远不为空 .
Link
Link
虽然这在我使用属性时非常有效,但它会扰乱序列化过程 .
简单的解决方法是改为标记基础对象以进行序列化 .
Link