Protobuf-Message相关类

本文详细介绍了 Protobuf 的消息类,包括MessageLite、Message和MessageFactory等。MessageLite是轻量级消息接口,提供编码和序列化功能;Message在MessageLite基础上增加了descriptors和reflection;MessageFactory是创建Message对象的接口,GeneratedMessageFactory是其实现,采用singleton模式。此外,文章还讨论了内部核心数据结构、关键接口及其功能,以及动态消息工厂DynamicMessageFactory。
部署运行你感兴趣的模型镜像

类MessageLite

所有message的接口类,从名字看是lite的message,普通message也是它的子类。

MessageLite适合“轻量级”的message(仅仅提供 encoding+序列化 功能,没有使用使用reflection和descriptors)。在确定可以使用“轻量级”的message的场景下,可以在.proto文件中如下增加配置(option optimize_for = LITE_RUNTIME;),来让protocol compiler产出MessageLite类型的类,这样可以节省runtime资源。

类Message

接口类,在类MessageLite的基础上增加了descriptors和reflection。

类MessageFactory

接口类,来创建Message对象,底层是封装了GeneratedMessageFactory类。

类GeneratedMessageFactory

MessageFactory的子类,singleton模式。

singleton模式是通过全局变量GeneratedMessageFactory* generated_message_factory_结合GOOGLE_PROTOBUF_DECLARE_ONCE(本质是pthread_once)来实现。

内部核心数据结构:

  1. hash_map<const char*, RegistrationFunc*>: 成员变量file_map_,从文件名到注册函数的映射关系,这个关系是在static初始化阶段完成,所以不需要锁;
  2. hash_map<const Descriptor*, const Message*>:成员变量type_map_Descriptor*到对应 Message*(这里其实是Message的prototype,调用它的New()接口,才创建具体的Message对象)的映射关系,这个关系会涉及多线程处理,使用读写锁保护;

对外关键接口:

const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type)

功能:

从descriptor找到对应message的prototype

处理流程:
  1. 上读锁,从hash_map<const Descriptor*, const Message*>找,有则返回、无则继续;
  2. 校验descriptor对应proto文件是否由全局的DescriptorPool管理;
  3. 用descriptor对应文件名从hash_map<const char*, RegistrationFunc*>找注册函数registration_func,无则返回、有则继续;
  4. 上写锁,判断是否有其它线程已经抢占(preempt)写入hash_map<const Descriptor*, const Message*>。如果没有,调用registration_func完成注册。并且从hash_map<const Descriptor*, const Message*>找到对应Message的prototype

void RegisterFile(const char* file, RegistrationFunc* registration_func)

功能:

注册file_name和对应的注册函数到hash_map<const char*, RegistrationFunc*>

void RegisterType(const Descriptor* descriptor, const Message* prototype)

功能:

注册descriptor和message的关系到hash_map<const Descriptor*, const Message*>

注册关系的生成:

在每个.pb.cc都会调用,例如protobuf/compiler/plugin.pb.cc 中:

    void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() {

    …… // 省略

      ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
        "google/protobuf/compiler/plugin.proto", &protobuf_RegisterTypes);                                                                                                      

    …… // 省略

}

注册函数定义也在protobuf/compiler/plugin.pb.cc 中:

    void protobuf_RegisterTypes(const ::std::string&) {
      protobuf_AssignDescriptorsOnce();
      ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
        CodeGeneratorRequest_descriptor_, &CodeGeneratorRequest::default_instance());
      ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
        CodeGeneratorResponse_descriptor_, &CodeGeneratorResponse::default_instance());
      ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
        CodeGeneratorResponse_File_descriptor_, &CodeGeneratorResponse_File::default_instance());
    }

针对plugin.proto中的每一个Message,都会有对应的descriptor和default message对象:

CodeGeneratorRequest_descriptor_和CodeGeneratorRequest::default_instance()
    void MessageFactory::InternalRegisterGeneratedMessage(
        const Descriptor* descriptor, const Message* prototype) {
      GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
}

最终是调用了 GeneratedMessageFactory::RegisterType():

    void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
                                               const Message* prototype) {
    …  // 省略
      if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) {
    …  // 省略
}

类DynamicMessageFactory

MessageFactory的子类,用于处理非compile-time的message。

相关类的关系图

avatar

您可能感兴趣的与本文相关的镜像

Llama Factory

Llama Factory

模型微调
LLama-Factory

LLaMA Factory 是一个简单易用且高效的大型语言模型(Large Language Model)训练与微调平台。通过 LLaMA Factory,可以在无需编写任何代码的前提下,在本地完成上百种预训练模型的微调

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值