我想了解为什么Marc Gravell开发的.NET 协议缓冲区解决方案如此之快。
我可以理解最初的 Google 解决方案是如何实现其性能的:它为对象序列化预先生成优化代码;我已经手工编写了一些序列化,并且知道如果避免反射,可以通过这种方式编写非常快的代码。但是 Marc 的库是一个运行时解决方案,它使用属性并且不生成任何生成的代码。那么它是怎样工作的 ?
我想了解为什么Marc Gravell开发的.NET 协议缓冲区解决方案如此之快。
我可以理解最初的 Google 解决方案是如何实现其性能的:它为对象序列化预先生成优化代码;我已经手工编写了一些序列化,并且知道如果避免反射,可以通过这种方式编写非常快的代码。但是 Marc 的库是一个运行时解决方案,它使用属性并且不生成任何生成的代码。那么它是怎样工作的 ?
protobuf-net 使用策略模式;根据需要(每种类型仅一次),它使用反射来查看类型,并构建一组可用于序列化和反序列化的序列化程序(基于公共接口) - 所以在使用时它只是逐步通过已知的一组序列化程序。
在这里面,它试图在与成员交谈时合理地使用反射;它用于Delegate.CreateDelegate
与属性对话,以及DynamicMethod
(和自定义 IL)与字段对话(如果可能;它取决于目标框架)。这意味着它总是与已知的委托类型交谈,而不仅仅是DynamicInvoke
(这很慢)。
在不发疯的情况下,代码确实在以下方面进行了一些优化(可以说是以牺牲可读性为代价):
byte[]
缓冲(输入/输出流)事后看来,我认为我在泛型点上犯了一个错误;复杂性意味着强制泛型进入系统会使它在一些地方变形,并在紧凑框架上积极地导致一些主要问题(对于复杂模型)。
我有一些设计(仅在我的脑海中)使用非泛型接口重构它,而是(对于合适的框架)更多地使用ILGenerator
(我的第一选择是Expression
,但这会强制使用更高的框架版本)。然而,问题是这需要相当长的时间才能开始工作,而且直到最近我都被淹没了。
最近我设法再次开始在 protobuf-net 上花费一些时间,所以希望我能清除我积压的请求等并尽快开始。我还打算让它与反射以外的模型一起工作(即单独描述线映射)。
并且不会产生任何生成的代码
我还应该澄清一下,如果您想使用生成的代码,有两个(可选的)代码生成路由;protogen.exe 或VS 插件允许从 .proto 文件生成代码。但这不是必需的 - 如果您有一个现有的 .proto 文件,或者打算与另一种语言(C++ 等)互操作以进行合同优先开发,这主要是有用的。
它的性能非常好!
您可以看到不同格式之间的全面比较,包括我完成的 protobuf - http://maxondev.com/serialization-performance-comparison-c-net-formats-frameworks-xmldatacontractserializer-xmlserializer-binaryformatter-json-newtonsoft-servicestack-text /
这种比较包括大小数据样本和不同的格式。
我的帖子中的一项测试-