英文:
How to safely recycle protobuf objects in golang
问题
我想要重复使用protobuf的消息对象来减少运行时的垃圾回收消耗,但我不确定是否安全。以下是用于测试的示例代码:
test.proto
message Hello{
uint32 id = 1;
}
test.pb.go
type Hello struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ID uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *Hello) Reset() {
*x = Hello{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_login_api_login_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
// 其他代码
main.go
func main() {
// 禁用垃圾回收以测试重新获取相同数据
gc := debug.SetGCPercent(-1)
// 作为protobuf对象池
cache := sync.Pool{New: func() interface{} { return &test.Hello{} }}
// 取出一个对象并使用它
m1 := cache.Get().(*test.Hello)
m1.ID = 999
fmt.Println(&m1.ID) // 打印 999
// 清空数据并将其放回对象池
m1.Reset()
cache.Put(m1)
// 再次取出一个对象并使用它
m2 := cache.Get().(*test.Hello)
fmt.Println(&m2.ID) // 打印 0
debug.SetGCPercent(gc)
}
英文:
I want to recycle the message object of protobuf to reduce GC consumption at runtime,but I'm not sure whether it's safe.The sample code for testing is as follows:
test.proto
message Hello{
uint32 id = 1;
}
test.pb.go
type Hello struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ID uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *Hello) Reset() {
*x = Hello{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_login_api_login_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
// other codes
main.go
func main() {
// Disable GC to test re-acquire the same data
gc := debug.SetGCPercent(-1)
// As a protobuf object pool
cache := sync.Pool{New: func() interface{} { return &test.Hello{} }}
// Take out an object and use it
m1 := cache.Get().(*test.Hello)
m1.ID = 999
fmt.Println(&m1.ID) // print 999
// Empty the data and put it back into the object pool
m1.Reset()
cache.Put(m1)
// Take out an object again and use it
m2 := cache.Get().(*test.Hello)
fmt.Println(&m2.ID) // print 0
debug.SetGCPercent(gc)
}
答案1
得分: 1
你展示的代码是安全的。当对象被放入池中后,像这样的池化操作会变得“不安全”,因为在引用对象之后仍然持有对它们的引用。这样做会导致竞态条件或奇怪的错误。因此,这也取决于使用你的对象的代码。
据我所知,协议缓冲区库和gRPC库不会保留对协议缓冲区对象的引用。这样做会破坏很多代码,因为这些库无法知道何时可以安全地重用对象。
因此,只要确保你自己的代码在将对象放入池中后不再使用它们,就应该是安全的。
英文:
The code you show is safe. Pooling like this becomes "unsafe" when references to objects are held after they are put into the pool. You risk race conditions or strange bugs. So it also depends on the code that uses your objects.
The protocol buffers library and gRPC libraries don't hold on to references to protobuf objects, as far as I know. Doing so would break a lot of code since such libraries have no way of knowing when it would be safe to reuse.
So as long as you make sure that your own code doesn't use objects after they are put in the pool, you should be good.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论