我可以重复使用空的或静态的 GRPC 响应吗?

问题描述 投票:0回答:1

使用 GRPC 的 Go 实现时,在多个请求之间重用或共享空或不变的响应的最佳实践是什么?这节省了不必要的分配 - 但有什么理由不这样做呢?

例如:

var emptyPingResponse = &pb.PingResponse{}
var staticBuildInfo  = &pb.GetBuildInfoResponse {
  Version:    /* ... */,
  BuildDate:  /* ... */,
}

func (*Service) Ping(ctx context.Context, req *pb.PingRequest) (res *pb.PingResponse, err error) {
  // do something here
  return emptyPingResponse, nil
}

func (*Service) GetBuildInfo(ctx context.Context, req *pb.GetBuildInfoRequest) (res *pb.GetBuildInfoResponse, err error) {
  return staticBuildInfo, nil
}
go protocol-buffers grpc grpc-go
1个回答
0
投票

我有一个想法,但我想讨论一下是否可行?
我使用sync.Pool来重用GRPC响应,因为我的响应数据太大了。

这是原创的

.pb.go

    func (c *noticeServiceClient) Notice(ctx context.Context, in *NoticeRequest, opts ...grpc.CallOption) (*NoticeResponse, error) {
        out := new(NoticeResponse)
        err := c.cc.Invoke(ctx, NoticeService_Notice_FullMethodName, in, out, opts...)
        if err != nil {
            return nil, err
        }
        return out, nil
    }

我没有更改它,但我向这个包中添加了另一个 go 文件。 (它们在同一个包装中)
我将使用

NoticeWithPoolResponse
代替原来的
Notice

这是我的代码。

package notice

import (

    context "context"
    grpc "google.golang.org/grpc"
    sync "sync"
    protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)

var noticeResponsePool = sync.Pool{
    New: func() interface{} {
        return new(NoticeResponse)
    },
}
type CustomNoticeServiceClient interface {
    NoticeWithPoolResponse (ctx context.Context, in *NoticeRequest, opts ...grpc.CallOption) (*NoticeResponse, error)
}

func NewCustomNoticeServiceClient(cc grpc.ClientConnInterface) CustomNoticeServiceClient {
    return &noticeServiceClient{cc}
}

func resetNoticeResponse(r *NoticeResponse) {
    // FIXME: check if clear builtin property is necessary
    r.state = protoimpl.MessageState{}
    r.sizeCache = 0
    r.unknownFields = protoimpl.UnknownFields{}

    // initial
    r.ErrCode = 0
    r.List = r.List[:0] // this is so bigggg
}

func (c *noticeServiceClient) NoticeWithPoolResponse(ctx context.Context, in *NoticeRequest, opts ...grpc.CallOption) (*NoticeResponse, error) {

    out := noticeResponsePool.Get().(*NoticeResponse)
    defer func () {
        resetNoticeResponse(out)
        noticeResponsePool.Put(out)
    }()

    err := c.cc.Invoke(ctx, NoticeService_Notice_FullMethodName, in, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}
© www.soinside.com 2019 - 2024. All rights reserved.