protobuf-net如何实现可观的性能?

Mic*_*elT 35 .net c# reflection protocol-buffers protobuf-net

我想了解为什么由Marc Gravell开发的协议缓冲解决方案的速度和它一样快.

我可以理解原始Google解决方案如何实现其性能:它预先生成用于对象序列化的优化代码; 我已经手工编写了一些序列化,并且知道如果避免反射,可以用这种方式编写相当快的代码.但Marc的库是一个运行时解决方案,它使用属性并且不会生成任何生成的代码.那么它是怎样工作的 ?

Mar*_*ell 44

protobuf-net使用策略模式; 根据需要(只有一种类型),它使用反射来查看类型,并构建一组序列化器(基于一个通用接口),它可以用来序列化和反序列化 - 所以在使用时它只是通过已知的步骤一系列序列化器.

其中,它试图在与成员交谈时合理地使用反射; 它用于Delegate.CreateDelegate与属性进行通信,以及DynamicMethod(和自定义IL)与字段进行通信(如果可能,它取决于目标框架).这意味着它始终与已知的委托类型进行对话,而不仅仅是DynamicInvoke(这非常慢).

在没有发疯的情况下,代码确实有一些优化(可以说是以可读性为代价):

  • 本地byte[]缓冲(输入/输出流)
  • 使用固定大小的数组(而不是列表等); 也许太多了
  • 使用泛型来避免拳击
  • 围绕二进制处理循环的许多调整/ twiddles/etc

事后看来,我认为我在仿制药方面犯了一个错误; 复杂性意味着迫使泛型进入系统使其在一些地方弯曲变形,并在紧凑框架上积极地引起一些主要问题(对于复杂模型).

我有一些设计(仅在我的脑海中)使用通用接口重构它,而是(对于合适的框架)更多地使用ILGenerator(我的第一选择会Expression,但这会强制更高的框架版本).然而,问题是这需要花费相当长的时间才能开始工作,直到最近我才淹没了.

最近我又成功地开始在protobuf网上花一些时间,所以希望我能清除积压的请求等,并尽快开始.这也是我打算把它处理模型的其他比反射(即单独描述线映射).


并且不生成任何生成的代码

我还应该澄清,如果你想使用生成的代码,有两个(可选的)codegen路由; protogen.exe或VS加载项允许从.proto文件生成代码.但这不是必需的 - 如果您有一个现有的.proto文件,或者想要与另一种语言(C++等)进行互操作以进行契约优先开发,那么它非常有用.