https://github.com/planetscale/vtprotobuf

此存储库提供插件,由 Vitess 用于生成优化的编解码和未马沙尔代码。protoc-gen-go-vtproto``protoc

此编译器生成的代码基于gogo/protobuf生成的优化代码,尽管此包不是原始编译器的叉子,因为它已实施以支持新的 ProtoBuf APIv2 包。gogo

可用功能

vtprotobuf作为辅助插件实施,必须与上游生成器一起运行,因为它生成完全兼容的辅助代码,以加快协议缓冲区消息的(去)序列化。protoc-gen-go

可生成以下功能:

  • size:生成一个与呼叫消息行为相同的帮手,但大小计算已完全展开,不使用反射。此帮助器功能可以直接使用,并且代码生成器还将使用该功能,以确保在 ProtoBuf 对象编组到它之前,目的地缓冲区大小正确。func (p *YourProto) SizeVT() int``proto.Size(p)``marshal
  • marshal:生成以下帮助方法
    • func (p *YourProto) MarshalVT() ([]byte, error):此功能的行为与调用相同,但实际编组已完全展开,不使用反射或分配内存。此功能只需通过调用消息来分配一个大小适当的缓冲区,然后用于编发信息。proto.Marshal(p)``SizeVT``MarshalToSizedBufferVT
    • func (p *YourProto) MarshalToVT(data []byte) (int, error):此功能可用于将消息编发到现有缓冲区。缓冲区必须足够大,以保持编组消息,否则此功能将恐慌。它返回编组的字节数。此功能是有用的,例如,当使用内存池来重复使用序列化缓冲器时。
    • func (p *YourProto) MarshalToSizedBufferVT(data []byte) (int, error):此功能的行为类似,但期望输入缓冲器具有保持消息所需的确切大小,否则会惊慌。MarshalTo
  • unmarshal:生成一个类似于调用消息的行为,但未存储是由展开的编解码器执行,而无需使用反射和分配尽可能少的内存。如果接收器完全归零,则未呼叫的实际行为将类似。这是因为 ProtoBuf API 中的实施是通过重置绝望消息,然后调用它。为了确保语义正确,请确保在呼叫前已调用邮件,或您的邮件已新分配。func (p *YourProto) UnmarshalVT(data []byte)``proto.Unmarshal(data, p)``p``proto.Merge(data, p)``proto.Unmarshal``proto.Merge``Unmarshal``proto.Reset``UnmarshalVT
  • pool:生成以下帮助方法
    • func (p *YourProto) ResetVT():此函数的行为与消息中的内存相同,但保留尽可能多的内存,因此对同一消息的进一步调用需要分配较少的内存。此 API 意为与内存池一起使用,不需要直接使用。proto.Reset(p)``UnmarshalVT
    • func (p *YourProto) ReturnToVTPool():此功能将消息返回到本地存储池,以便以后可以重复使用。在将对象存储在池中之前,它会正确清除对象。此方法仅应用于通过呼叫从内存池获得的消息。调用此方法后使用p会导致未定义的行为p``ResetVT``YourProtoFromVTPool
    • func YourProtoFromVTPool() *YourProto:此功能从本地内存池返回消息,或在池当前为空时分配新消息。返回的消息始终是空的,并准备使用(例如,通过调用它)。消息处理完毕后,必须通过调用将其返回到存储池。将消息返回到池不是强制性的(它不会泄露内存),但如果您不返回它,则会破坏内存池的全部点。YourProto``UnmarshalVT``ReturnToVTPool()

用法

  1. 安装:protoc-gen-go-vtproto
  1. go install github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto
  1. 确保您的项目已经使用原型购买 v2 API(即)。编译器与 APIV1 生成的代码不兼容。google.golang.org/protobuf``vtprotobuf
  2. 更新发电机以使用新插件。维特斯的示例:protoc
  1. for name in $(PROTO_SRC_NAMES); do \
  2. $(VTROOT)/bin/protoc \
  3. --go_out=. --plugin protoc-gen-go="${GOBIN}/protoc-gen-go" \
  4. --go-grpc_out=. --plugin protoc-gen-go-grpc="${GOBIN}/protoc-gen-go-grpc" \
  5. --go-vtproto_out=. --plugin protoc-gen-go-vtproto="${GOBIN}/protoc-gen-go-vtproto" \
  6. --go-vtproto_opt=features=marshal+unmarshal+size \
  7. proto/$${name}.proto; \
  8. done

请注意,编译器运行像辅助插件到 APIv2,就像新的 GRPC 编译器插件一样。您需要与上游发电机一起运行,而不是作为替换。vtproto``protoc-gen-go``protoc-gen-go-grpc

  1. (可选)传递您想要生成的功能。如果没有提供任何功能,将执行所有编码步骤。--go-vtproto_opt
  2. 编译项目中的文件。您应该看到文件旁边的文件和已经生成的文件。.proto``_vtproto.pb.go``.pb.go``_grpc.pb.go
  3. (可选)切换 RPC 框架以使用优化的帮助人员(参见以下部分)

使用带 RPC 框架的优化代码

编译器不会覆盖任何默认编组或未覆盖的原型对象代码。相反,它生成可明确称为”选择加入更快(去)序列化”的帮手方法。protoc-gen-go-vtproto

vtprotobuf与格瑞普

要使用新版本的 GRPC,您需要注册包提供的编年代码。vtprotobuf``github.com/planetscale/vtprotobuf/codec/grpc

  1. package servenv
  2. import (
  3. "github.com/planetscale/vtprotobuf/codec/grpc"
  4. "google.golang.org/grpc/encoding"
  5. _ "google.golang.org/grpc/encoding/proto"
  6. )
  7. func init() {
  8. encoding.RegisterCodec(grpc.Codec{})
  9. }

请注意,我们执行一个空白导入的默认编码,船舶与GRPC,以确保它被替换后,我们。所提供的编解码器将使用优化的编解码器对所有 ProtoBuf 消息进行序列化和去除化。_ "google.golang.org/grpc/encoding/proto"``proto

特维尔普

实际上,我不知道如何切换Twirp中的编码器。也许这甚至是不可能的。

博士

要用作 DRPC 编码,只需在调用中作为标志传递即可。vtprotobuf``github.com/planetscale/vtprotobuf/codec/drpc``protolib``protoc-gen-go-drpc

例:

  1. protoc --go_out=. --go-vtproto_out=. --go-drpc_out=. --go-drpc_opt=protolib=github.com/planetscale/vtprotobuf/codec/drpc