【问题标题】:protobuf-net documentation or alternativesprotobuf-net 文档或替代品
【发布时间】:2013-09-19 22:06:30
【问题描述】:

Protobuf-net 似乎是最快的,并且对于高性能需要最推荐的 .NET 序列化库。我真的很想使用它,因为我需要通过网络发送数十万个对象。

但是,我在开始时遇到了问题。文档(github 上的 wiki)非常稀少,尤其是对于 v2。

不知何故,你们似乎能够开始使用 lib。如何?通过阅读来源?试错?还是有一些我不知道的 API 文档/教程? (我只知道 GitHib 页面。)

感谢和欢呼,

一月

P.S.:我需要开始使用 RuntimeTypeModel(POCO 没有属性)。

【问题讨论】:

标签: .net serialization protobuf-net


【解决方案1】:

既然您还询问了替代方案...

不需要属性修饰是创建 Migrant 的原因之一,这是一个具有简单 API 的快速序列化库。该库有一些在 protobuf 中也存在的想法(因此我们在速度和大小方面或多或少是相当的),但同时尝试解决不同的问题。在与 protobuf 不同的特性中,空集合和 null 集合之间存在区别,并且整个序列化是基于引用的引用和基于值的值(当然,您也可以将引用视为一种特殊的值)。 github 上的 README 应该可以回答你的大部分问题;是否需要一些更详细的信息,请问。

自定义对象序列化的简单场景:

var stream = new MyCustomStream();
var myComplexObject = new MyComplexType(complexParameters);
var serializer = new Serializer();

serializer.Serialize(myComplexObject, stream);

stream.Seek(0, SeekOrigin.Begin);

var myDeserializedObject = serializer.Deserialize<MyComplexType>(stream);

注意Deserialize 中的预期类型仅用于具有良好的反序列化对象的编译时类型,您也可以使用通用的object

免责声明:我是开发人员之一。

【讨论】:

    【解决方案2】:

    在 protobuf 中,类型的每个成员都需要一个标识号,因为 protobuf 是基于数字的(它不发送名称)。因此,诀窍很简单:告诉它使用什么数字。例如:

    class Customer {
        public int Id {get;set;}
        public string Name {get;set;}
    }
    

    为此指定合同的最简单方法是:

    RuntimeTypeModel.Default.Add(typeof(Customer), false).Add("Id", "Name");
    

    它将Id 与 1 关联,Name 与 2 关联。使用属性时,有一些内置的“自己弄清楚”代码,我应该在非属性 API 上真正公开这些代码 - 例如:

    • 按字母顺序序列化所有公共字段 + 属性
    • 按字母顺序序列化所有字段(公共或非公共)

    但是:这两种方法都可以通过反射来实现。请注意,无论哪种情况,如果类型可能在某些时候发生变化,使用反射是解决问题的好方法。

    可能有帮助的其他功能,我可以提供更多信息:

    • 可以指定类型工厂(全局或每个实例),这对于预填充值或使用可用对象池很有用
    • 可以为复杂的场景编写代理类型 - 当大多数模型工作正常时,这很有用,但是一种类型太深奥而不适合序列化 - 但是可以设计一种替代布局,您可以编写双向转换代码
    • 默认情况下,许多看起来像“元组”的东西都会被处理 - 特别是,如果它是公共不可变的,并且有一个接受与所有公共成员匹配的参数的构造函数 - 它会假定序列化构造函数指定的顺序

    【讨论】:

    • RuntimeTypeModel.Compile() 需要相当长的时间......添加一个具有 20 个属性的类型大约需要 3 秒。我错过了什么吗?干杯,简
    • @Knack 我怀疑其中很多是融合/JIT等-我的测试台中有一个模型,每个Compile()有20个属性3ms(不是s);对于有意复杂的模型(801 种类型,1600 个属性),每个 Compile 需要 600 毫秒。我很想看看那里发生了什么。另请注意:在大多数情况下,您不需要调用Compile() - 它会根据需要自动执行每种类型的编译
    • 我的设置有问题(不确定我是否在这些运行中启用了 IntelliTrace ......)。不管怎样:现在我得到了一致的预期性能数据——有和没有 Compile()。真的,真的很棒,令人印象深刻。谢谢!
    • @Knack heh;我做了很多性能工作——我总是关闭的第一件事是智能跟踪。还;您需要在“发布”模式下运行,并且 在 IDE 之外 - 获取有意义的数字。否则,您实际上只是在分析 IDE/调试器。
    【解决方案3】:

    另一个选项是Dasher(可通过NuGet 获得)。

    它是一个简单、快速、轻量级的 .NET 序列化器和反序列化器,适用于 C# 类型,无需任何属性或其他修饰。

    var stream = new MemoryStream();
    
    // serialise to stream
    new Serialiser<Holiday>().Serialise(stream, christmas);
    
    stream.Position = 0;
    
    // deserialise from stream
    var christmas = new Deserialiser<Holiday>().Deserialise(stream);
    

    它使用反射发射在运行时产生高度优化的序列化和反序列化函数。底层编码是自描述的 MsgPack,比网络上的 protobuf 略大,但这确实意味着您可以解码收到的任何消息,包括属性名称、类型和值。

    免责声明:我编写了这个库。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-18
      • 2011-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-05
      • 2011-03-29
      相关资源
      最近更新 更多