阅读Protobuf官网的一些笔记

阅读 Protobuf 官网的一些笔记

Protobuf API(The Protocol Buffer API)

  • 每一个字段都会有基本的 set_ get_ 方法
  • string类型的字段可使用 mutable_方法来直接得到字符串的指针。
  • 若是是optional 修饰的类型, 在没有对string类型赋值时也可使用这个方法 mutable_方法,由于会帮咱们自动初始化为 empty string 。
  • 可重复修改字段 Repeated fields 有特殊的方法:
    • _size
    • 获取字段特定的一位数字
    • 更新现有的字段
    • add_方法,能够添加新的值以便后面修改

通用的方法(Standard Message Methods)

  • bool IsInitialized() const;(判断当前字段是否被初始化)
  • string DebugString() const;(转换为字符串的形式,方便调试查看)
  • void CopyFrom(const Person& from);(重写给定的消息结构)
  • void Clear();(清除全部元素,返回空)

序列化与反序列化(Parsing and Serialization

  • 字符串形式:
    • bool SerializeToString(string* output) const;
    • bool ParseFromString(const string& data);
  • 文件中持久化:
    • bool SerializeToOstream(ostream* output) const;
    • bool ParseFromIstream(istream* input);

google提到:正则表达式

Protocol Buffers and O-O Design Protocol buffer classes are basically dumb data holders (like structs in C); they don't make good first class citizens in an object model. If you want to add richer behaviour to a generated class, the best way to do this is to wrap the generated protocol buffer class in an application-specific class. Wrapping protocol buffers is also a good idea if you don't have control over the design of the .proto file (if, say, you're reusing one from another project). In that case, you can use the wrapper class to craft an interface better suited to the unique environment of your application: hiding some data and methods, exposing convenience functions, etc. You should never add behaviour to the generated classes by inheriting from them. This will break internal mechanisms and is not good object-oriented practice anyway.api

特别提到 Protobuf 是根据面向对象设计的设计理念来设计的。因此咱们能够把面向对象设计的设计思路应用其中。数据结构

  • 原生的protobuf Message功能是比较单一的,能够把protobuf的结构化数据经过应用程序来进一步封装,达到功能更丰富的地步。

继承Protobuf数据结构(Extending a Protocol Buffer)

为了使Protobuf拥有向前兼容,向后拓展的能力,须要按照以下作:app

  • 不能够改变标签的数字。由于这个是Protobuf在存储时的key啊。
  • 不能够添加或删除 required 修饰的字段
  • 能够删除 optionalrepeated 字段
  • 能够添加新的 optionalrepeated 修饰的字段,可是标签须要是惟一不冲突的。

从这里能够看到,Protobuf在底层的存储方式是 Tag-Length-Value,标识-长度-字段值。其中的Length是可选的。ide

为了兼容和健壮,字段被删除或者更新时,对于应用程序来讲是透明的(对于旧代码,已删除的可选字段将只有默认值,已删除的重复字段将为空。新代码还将透明地读取旧消息),最好是在定义字段最后加上默认值,而且是在使用时先经过 has_方法 来判断该字段是否存在。优化

  • 默认值
    • string(NULL)
    • booleans(false)
    • number(0)

优化建议(Optimization Tips)

Protobuf已经被极度优化过了,因此才有现在的这么高效,可是还能够提供下面几个建议达到更优:ui

尽量复用消息对象。即便在清除内存时,消息依然保留分配给它们的任何内存,以便未来复用。所以,若是正在连续处理许多具备相同类型和相似结构的消息,那么最好每次复用相同的消息对象,以减轻内存分配器的负载。然而,随着时间的推移,对象可能会变得膨胀,特别是当您的消息在“形状”上发生变化时,或者若是您偶尔构造一个比一般大得多的消息时。您应该经过调用SpaceUsed方法来监视消息对象的大小,并在达到某个大小时强制删除对象释放内存。this

系统默认的内存分配器经过多个线程分配大量小对象时优化可能不太好,能够尝试使用googletcmalloc代替。google

高级用法(Advanced Usage)

Protobuf的一个关键特性是反射。咱们能够遍历消息的字段并操做它们的值,而无需针对任何特定的消息类型编写代码。编码

使用反射的一种很是有用的方法是将Protobuf消息格式转换为其余编码(如XMLJSON)。

反射更高级的用途多是查找同一类型的两个消息之间的差别,或者开发一种“协议消息正则表达式”,能够在其中编写匹配特定消息内容的表达式。这样就能够实现动态的修改消息结构,达到运行时修改协议类型。

相关文章
相关标签/搜索