golang通用对象池管理插件库go-commons-pool的使用
Go Commons Pool 使用指南
Go Commons Pool 是一个 Golang 的通用对象池管理库,直接从 Apache Commons Pool 重写而来。
特性
- 支持自定义 PooledObjectFactory
- 丰富的池配置选项,可以精确控制池化对象的生命周期
- 池的 LIFO(后进先出)或 FIFO(先进先出)策略
- 池容量配置
- 池对象验证配置
- 池对象借用阻塞和最大等待时间配置
- 池对象驱逐配置
- 池对象放弃配置
池配置选项
选项 | 默认值 | 描述 |
---|---|---|
LIFO | true | 池是否为 LIFO(后进先出) |
MaxTotal | 8 | 池的容量上限 |
MaxIdle | 8 | 池中最大空闲实例数 |
MinIdle | 0 | 池中最小空闲实例数 |
TestOnCreate | false | 对象创建时是否验证 |
TestOnBorrow | false | 对象借出时是否验证 |
TestOnReturn | false | 对象归还时是否验证 |
TestWhileIdle | false | 对象空闲时是否验证 |
BlockWhenExhausted | true | 池耗尽时是否阻塞 |
MinEvictableIdleTime | 30m | 最小可驱逐空闲时间 |
SoftMinEvictableIdleTime | math.MaxInt64 | 软最小可驱逐空闲时间 |
NumTestsPerEvictionRun | 3 | 每次驱逐检查的对象数 |
TimeBetweenEvictionRuns | 0 | 驱逐检查间隔时间(毫秒) |
使用方法
使用简单工厂
import (
"context"
"fmt"
"strconv"
"sync/atomic"
"github.com/jolestar/go-commons-pool/v2"
)
func Example_simple() {
type myPoolObject struct {
s string
}
v := uint64(0)
factory := pool.NewPooledObjectFactorySimple(
func(context.Context) (interface{}, error) {
return &myPoolObject{
s: strconv.FormatUint(atomic.AddUint64(&v, 1), 10),
},
nil
})
ctx := context.Background()
p := pool.NewObjectPoolWithDefaultConfig(ctx, factory)
obj, err := p.BorrowObject(ctx)
if err != nil {
panic(err)
}
o := obj.(*myPoolObject)
fmt.Println(o.s)
err = p.ReturnObject(ctx, obj)
if err != nil {
panic(err)
}
// Output: 1
}
使用自定义工厂
import (
"context"
"fmt"
"strconv"
"sync/atomic"
"github.com/jolestar/go-commons-pool/v2"
)
type MyPoolObject struct {
s string
}
type MyCustomFactory struct {
v uint64
}
func (f *MyCustomFactory) MakeObject(ctx context.Context) (*pool.PooledObject, error) {
return pool.NewPooledObject(
&MyPoolObject{
s: strconv.FormatUint(atomic.AddUint64(&f.v, 1), 10),
}),
nil
}
func (f *MyCustomFactory) DestroyObject(ctx context.Context, object *pool.PooledObject) error {
// 销毁对象逻辑
return nil
}
func (f *MyCustomFactory) ValidateObject(ctx context.Context, object *pool.PooledObject) bool {
// 验证对象逻辑
return true
}
func (f *MyCustomFactory) ActivateObject(ctx context.Context, object *pool.PooledObject) error {
// 激活对象逻辑
return nil
}
func (f *MyCustomFactory) PassivateObject(ctx context.Context, object *pool.PooledObject) error {
// 钝化对象逻辑
return nil
}
func Example_customFactory() {
ctx := context.Background()
p := pool.NewObjectPoolWithDefaultConfig(ctx, &MyCustomFactory{})
p.Config.MaxTotal = 100
obj1, err := p.BorrowObject(ctx)
if err != nil {
panic(err)
}
o := obj1.(*MyPoolObject)
fmt.Println(o.s)
err = p.ReturnObject(ctx, obj1)
if err != nil {
panic(err)
}
// Output: 1
}
注意事项
PooledObjectFactory.MakeObject 必须返回指针,而不是值。以下代码会报错:
p := pool.NewObjectPoolWithDefaultConfig(ctx, pool.NewPooledObjectFactorySimple(
func(context.Context) (interface{}, error) {
return "hello", nil
}))
obj, _ := p.BorrowObject()
p.ReturnObject(obj)
正确的方式是:
p := pool.NewObjectPoolWithDefaultConfig(ctx, pool.NewPooledObjectFactorySimple(
func(context.Context) (interface{}, error) {
s := "hello"
return &s, nil
}))
性能测试
运行 pool_perf_test 的结果几乎与 Java 版本相同:
go test --perf=true
对于 Apache Commons Pool 用户
- 直接使用 pool.Config.xxx 来更改池配置
- 默认配置值与 Java 版本相同
- 如果在创建 ObjectPool 后更改了 TimeBetweenEvictionRuns,应该调用 ObjectPool.StartEvictor 使其生效
- 没有 KeyedObjectPool (TODO)
- 没有 ProxiedObjectPool
- 没有池统计信息 (TODO)
如何贡献
- 选择一个要解决的开放问题,如果没有则创建一个并描述您想要更改的内容
- 在 GitHub 上 fork 仓库
- 编写代码解决问题
- 创建 PR 并链接到问题
- 确保测试和覆盖率通过
- 等待维护者合并
许可证
Go Commons Pool 采用 Apache License, Version 2.0 许可证。
更多关于golang通用对象池管理插件库go-commons-pool的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang通用对象池管理插件库go-commons-pool的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
go-commons-pool 使用指南
go-commons-pool 是一个通用的 Golang 对象池管理库,类似于 Java 的 Apache Commons Pool。它提供了高效的对象池管理功能,适用于需要频繁创建和销毁对象的场景,如数据库连接池、网络连接池等。
基本概念
- ObjectPool: 对象池接口,定义了借出、归还对象等基本操作
- PooledObject: 池中管理的对象包装器
- PooledObjectFactory: 对象工厂接口,负责创建、销毁和验证对象
安装
go get github.com/jolestar/go-commons-pool/v2
基本使用示例
1. 定义池化对象
首先定义一个需要被池化的对象类型:
type MyObject struct {
Name string
// 其他字段...
}
2. 实现对象工厂
实现 PooledObjectFactory
接口:
type MyObjectFactory struct{}
func (f *MyObjectFactory) MakeObject(ctx context.Context) (*pool.PooledObject, error) {
obj := &MyObject{
Name: fmt.Sprintf("obj-%d", time.Now().UnixNano()),
}
return pool.NewPooledObject(obj), nil
}
func (f *MyObjectFactory) DestroyObject(ctx context.Context, object *pool.PooledObject) error {
// 清理资源
return nil
}
func (f *MyObjectFactory) ValidateObject(ctx context.Context, object *pool.PooledObject) bool {
// 验证对象是否有效
return true
}
func (f *MyObjectFactory) ActivateObject(ctx context.Context, object *pool.PooledObject) error {
// 激活对象
return nil
}
func (f *MyObjectFactory) PassivateObject(ctx context.Context, object *pool.PooledObject) error {
// 钝化对象
return nil
}
3. 创建对象池
func createObjectPool() *pool.ObjectPool {
factory := &MyObjectFactory{}
config := pool.NewDefaultPoolConfig()
// 配置池参数
config.MaxTotal = 10 // 最大对象数
config.MaxIdle = 5 // 最大空闲对象数
config.MinIdle = 1 // 最小空闲对象数
config.BlockWhenExhausted = true // 当池耗尽时是否阻塞
config.MaxWaitMillis = 3000 // 最大等待毫秒数
config.TestOnBorrow = true // 借出时是否验证
config.TestOnReturn = true // 归还时是否验证
config.TestWhileIdle = true // 空闲时是否验证
return pool.NewObjectPool(context.Background(), factory, config)
}
4. 使用对象池
func main() {
objectPool := createObjectPool()
defer objectPool.Close(context.Background())
// 从池中借出对象
obj, err := objectPool.BorrowObject(context.Background())
if err != nil {
log.Fatal(err)
}
// 类型断言获取实际对象
myObj := obj.(*MyObject)
fmt.Println("使用对象:", myObj.Name)
// 使用完毕后归还对象
err = objectPool.ReturnObject(context.Background(), obj)
if err != nil {
log.Fatal(err)
}
// 统计信息
stats := objectPool.GetNumActive()
fmt.Println("活跃对象数:", stats)
}
高级功能
1. 带超时的借出
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
obj, err := objectPool.BorrowObject(ctx)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
fmt.Println("借出对象超时")
} else {
log.Fatal(err)
}
}
2. 自动回收泄漏对象
config := pool.NewDefaultPoolConfig()
config.TimeBetweenEvictionRuns = 30 * time.Second // 回收间隔
config.MinEvictableIdleTime = 10 * time.Minute // 最小空闲时间
3. 自定义对象验证
func (f *MyObjectFactory) ValidateObject(ctx context.Context, object *pool.PooledObject) bool {
obj := object.Object.(*MyObject)
// 自定义验证逻辑
return obj.Name != "" // 示例验证
}
最佳实践
- 合理配置池大小:根据系统资源和实际需求设置 MaxTotal 和 MaxIdle
- 及时归还对象:使用 defer 确保对象归还
- 处理对象失效:在 ValidateObject 中实现严格的验证逻辑
- 监控池状态:定期检查 NumActive、NumIdle 等统计信息
- 避免泄漏:确保所有借出的对象最终都被归还
完整示例
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/jolestar/go-commons-pool/v2"
)
type MyObject struct {
ID string
Data string
}
type MyObjectFactory struct{}
func (f *MyObjectFactory) MakeObject(ctx context.Context) (*pool.PooledObject, error) {
obj := &MyObject{
ID: fmt.Sprintf("obj-%d", time.Now().UnixNano()),
Data: "initial data",
}
return pool.NewPooledObject(obj), nil
}
func (f *MyObjectFactory) DestroyObject(ctx context.Context, object *pool.PooledObject) error {
// 清理资源
return nil
}
func (f *MyObjectFactory) ValidateObject(ctx context.Context, object *pool.PooledObject) bool {
obj := object.Object.(*MyObject)
return obj.ID != "" && obj.Data != ""
}
func (f *MyObjectFactory) ActivateObject(ctx context.Context, object *pool.PooledObject) error {
// 激活逻辑
return nil
}
func (f *MyObjectFactory) PassivateObject(ctx context.Context, object *pool.PooledObject) error {
// 钝化逻辑
return nil
}
func main() {
factory := &MyObjectFactory{}
config := pool.NewDefaultPoolConfig()
config.MaxTotal = 5
config.MaxIdle = 3
config.MinIdle = 1
pool := pool.NewObjectPool(context.Background(), factory, config)
defer pool.Close(context.Background())
// 使用对象
for i := 0; i < 10; i++ {
go func(i int) {
obj, err := pool.BorrowObject(context.Background())
if err != nil {
log.Printf("协程 %d 借出失败: %v", i, err)
return
}
myObj := obj.(*MyObject)
log.Printf("协程 %d 使用对象 %s", i, myObj.ID)
// 模拟工作
time.Sleep(time.Duration(i%3+1) * time.Second)
err = pool.ReturnObject(context.Background(), obj)
if err != nil {
log.Printf("协程 %d 归还失败: %v", i, err)
}
}(i)
}
time.Sleep(5 * time.Second)
log.Printf("最终统计 - 活跃: %d, 空闲: %d",
pool.GetNumActive(), pool.GetNumIdle())
}
go-commons-pool 提供了灵活且强大的对象池管理功能,通过合理配置可以显著提高应用程序性能,特别是在高并发场景下需要频繁创建销毁对象的场景。