From c439ef6424f67bddb3a391ee56289510da628909 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Fri, 12 Jan 2024 12:51:49 +0800 Subject: [PATCH] =?UTF-8?q?test:=20=E5=AE=8C=E5=96=84=20hub.ObjectPool=20?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/hub/object_pool.go | 12 ++-- utils/hub/object_pool_example_test.go | 22 +++++++ utils/hub/object_pool_test.go | 92 +++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 utils/hub/object_pool_example_test.go diff --git a/utils/hub/object_pool.go b/utils/hub/object_pool.go index c041ae8..7ea9247 100644 --- a/utils/hub/object_pool.go +++ b/utils/hub/object_pool.go @@ -1,16 +1,14 @@ package hub import ( - "errors" + "fmt" "sync" ) -// NewObjectPool 创建一个线程安全的对象缓冲池 -// - 通过 Get 获取一个对象,如果缓冲区内存在可用对象则直接返回,否则新建一个进行返回 -// - 通过 Release 将使用完成的对象放回缓冲区,超出缓冲区大小的对象将被放弃 +// NewObjectPool 创建一个 ObjectPool func NewObjectPool[T any](generator func() *T, releaser func(data *T)) *ObjectPool[*T] { if generator == nil || releaser == nil { - panic(errors.New("generator or releaser is nil")) + panic(fmt.Errorf("generator and releaser can not be nil, generator check: %v, releaser check: %v", generator != nil, releaser != nil)) } return &ObjectPool[*T]{ releaser: releaser, @@ -22,10 +20,8 @@ func NewObjectPool[T any](generator func() *T, releaser func(data *T)) *ObjectPo } } -// ObjectPool 线程安全的对象缓冲池 +// ObjectPool 基于 sync.Pool 实现的线程安全的对象池 // - 一些高频临时生成使用的对象可以通过 ObjectPool 进行管理,例如属性计算等 -// - 缓冲区内存在可用对象时直接返回,否则新建一个进行返回 -// - 通过 Release 将使用完成的对象放回缓冲区,超出缓冲区大小的对象将被放弃 type ObjectPool[T any] struct { p sync.Pool releaser func(data T) diff --git a/utils/hub/object_pool_example_test.go b/utils/hub/object_pool_example_test.go new file mode 100644 index 0000000..73d267f --- /dev/null +++ b/utils/hub/object_pool_example_test.go @@ -0,0 +1,22 @@ +package hub_test + +import ( + "fmt" + "github.com/kercylan98/minotaur/utils/collection" + "github.com/kercylan98/minotaur/utils/hub" +) + +func ExampleNewObjectPool() { + var p = hub.NewObjectPool[map[int]int](func() *map[int]int { + return &map[int]int{} + }, func(data *map[int]int) { + collection.ClearMap(*data) + }) + + m := *p.Get() + m[1] = 1 + p.Release(&m) + fmt.Println(m) + // Output: + // map[] +} diff --git a/utils/hub/object_pool_test.go b/utils/hub/object_pool_test.go index e3fc1df..6d9bb91 100644 --- a/utils/hub/object_pool_test.go +++ b/utils/hub/object_pool_test.go @@ -1 +1,93 @@ package hub_test + +import ( + "github.com/kercylan98/minotaur/utils/hub" + "testing" +) + +func TestNewObjectPool(t *testing.T) { + var cases = []struct { + name string + generator func() *map[string]int + releaser func(data *map[string]int) + shouldPanic bool + }{ + {name: "TestNewObjectPool_NilGenerator", generator: nil, releaser: func(data *map[string]int) {}, shouldPanic: true}, + {name: "TestNewObjectPool_NilReleaser", generator: func() *map[string]int { return &map[string]int{} }, releaser: nil, shouldPanic: true}, + {name: "TestNewObjectPool_NilGeneratorAndReleaser", generator: nil, releaser: nil, shouldPanic: true}, + {name: "TestNewObjectPool_Normal", generator: func() *map[string]int { return &map[string]int{} }, releaser: func(data *map[string]int) {}, shouldPanic: false}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + defer func() { + if err := recover(); c.shouldPanic && err == nil { + t.Error("TestNewObjectPool should panic") + } + }() + _ = hub.NewObjectPool[map[string]int](c.generator, c.releaser) + }) + } +} + +func TestObjectPool_Get(t *testing.T) { + var cases = []struct { + name string + generator func() *map[string]int + releaser func(data *map[string]int) + }{ + { + name: "TestObjectPool_Get_Normal", + generator: func() *map[string]int { + return &map[string]int{} + }, + releaser: func(data *map[string]int) { + for k := range *data { + delete(*data, k) + } + }, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + pool := hub.NewObjectPool[map[string]int](c.generator, c.releaser) + if actual := pool.Get(); len(*actual) != 0 { + t.Error("TestObjectPool_Get failed") + } + }) + } +} + +func TestObjectPool_Release(t *testing.T) { + var cases = []struct { + name string + generator func() *map[string]int + releaser func(data *map[string]int) + }{ + { + name: "TestObjectPool_Release_Normal", + generator: func() *map[string]int { + return &map[string]int{} + }, + releaser: func(data *map[string]int) { + for k := range *data { + delete(*data, k) + } + }, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + pool := hub.NewObjectPool[map[string]int](c.generator, c.releaser) + msg := pool.Get() + m := *msg + m["test"] = 1 + pool.Release(msg) + if len(m) != 0 { + t.Error("TestObjectPool_Release failed") + } + }) + } +}