grpc

grpc压缩编解码

Posted by Liangjf on July 20, 2020

grpc压缩编解码

encoding/encoding.go:23

源码分析

压缩接口

type Compressor interface {
	Compress(w io.Writer) (io.WriteCloser, error)
	Decompress(r io.Reader) (io.Reader, error)
	Name() string
}

编码接口

type Codec interface {
	Marshal(v interface{}) ([]byte, error)
	Unmarshal(data []byte, v interface{}) error
	Name() string
}

默认支持protobuf编码组件, gzip压缩组件

从protobuf编码组件看对象池应用

对象池创建, 对象是proto.Buffer{}

```go
var protoBufferPool = &sync.Pool{
	New: func() interface{} {
		return &cachedProtoBuffer{
			Buffer:            proto.Buffer{},
			lastMarshaledSize: 16,
		}
	},
}
```

从对象池取出一个protobuf对象, 塞入数据, 调用反序列化, 清空protobuf, 将protobuf对象放回对象池中

```go
func (codec) Unmarshal(data []byte, v interface{}) error {
	protoMsg := v.(proto.Message)
	protoMsg.Reset()

	if pu, ok := protoMsg.(proto.Unmarshaler); ok {
		// object can unmarshal itself, no need for buffer
		return pu.Unmarshal(data)
	}

	//从对象池取出一个protobuf对象, 塞入数据, 调用反序列化, 清空protobuf, 将protobuf对象放回对象池中
	cb := protoBufferPool.Get().(*cachedProtoBuffer)
	cb.SetBuf(data)
	err := cb.Unmarshal(protoMsg)
	cb.SetBuf(nil)
	protoBufferPool.Put(cb)
	return err
}
```

从对象池取出一个protobuf对象, 序列化对象得到字节码, 清空protobuf, 将protobuf对象放回对象池中

```go
func (codec) Marshal(v interface{}) ([]byte, error) {
	if pm, ok := v.(proto.Marshaler); ok {
		// object can marshal itself, no need for buffer
		return pm.Marshal()
	}

	cb := protoBufferPool.Get().(*cachedProtoBuffer)

	protoMsg := v.(proto.Message)
	newSlice := make([]byte, 0, cb.lastMarshaledSize)
	cb.SetBuf(newSlice)
	cb.Reset()
	if err := cb.Marshal(protoMsg); err != nil {
		return nil, err
	}
	out := cb.Bytes()
	cb.lastMarshaledSize = capToMaxInt32(len(out))

	// put back buffer and lose the ref to the slice
	cb.SetBuf(nil)
	protoBufferPool.Put(cb)
	return out, err
}
```

这里grpc关于编解码的对象池应用, 看起来代码多, 其实就是go src对象池的应用

对象池使用步骤

  • 创建对象池
  • 从池中取出对象Get()
  • 使用对象处理自己的逻辑
  • 把对象放入池中Put()