标题对象池的实现
原料
- channel
- select
- 对象本身
import (
"time"
"errors"
)
type MyObject struct {
Value interface{}
}
type ObjectPool struct {
objectChan chan *MyObject
}
//初始化程序
func PoolInit(size int) (*ObjectPool, error) {
objP:= new(ObjectPool)
objP.objectChan = make(chan *MyObject, size)
for a:= 0 ; a < size ; a++ {
obj := new (MyObject)
objP.objectChan <- obj
}
return objP , nil
}
实现思路
- 在初始化的时候,按照指示将对象放入有buffer的chan里面存储
- get的时候就从chan里面获取一个对象返回,并且设置超时时间,如果超过时间没有其他的人去释放就会返回超时错误。
- release的时候需要看当前的buffer是否已经满了,如果写不进去的话就要返回错误。
func (this *ObjectPool) GetObject(timeout time.Duration) (*MyObject , error) {
select {
case ret:= <- this.objectChan:
return ret,nil
case <-time.After(timeout):
return nil , errors.New("time out")
}
}
func (this *ObjectPool) RleaseObject (obj *MyObject ) (error ) {
select {
case this.objectChan <- obj :
return nil
default: //如果没有接收的chan的话就说明缓存区已经满了
return errors.New("overload")
}
}
测试程序:使用go test命令运行
package objectPool_test
import (
"testing"
"time"
"objectPool"
)
func TestObjectPool(t *testing.T) {
pool, err := objectPool.PoolInit(5)
if err != nil { return }
for i := 0 ; i < 5; i++ {
if _, err := pool.GetObject(time.Second * 1); err != nil {
t.Error(err)
}
}
/*
for i := 0 ; i < 5 ; i++ {
if err := pool.RleaseObject(); err != nil {
t.Error(err)
}
}
*/
}
系统自带之 sync.Pool
系统里卖你也带了一个sync.Pool但是与其说是对象池不如理解为一个缓存池,这个缓存池的结构分为两种。sync其实是与processor有关系的。sync.Pool在每一个processor的存储主要分两部分
- 私有对象 :并发安全的存在
- 共享池:并发不安全需要加锁进行并发控制等
在协程内部从pool里面获取一个对象时,如果私有对象存在就直接返回私有对象。如果私有对象不存在的时候就会去共享池里面寻找。
共享池的共享体现在,如果一个协程里面的共享池没数据之后他还会去寻找当前所有用到sync.pool的协程的共享池,去获取别的协程里面的内容。
实在都没有了的话就会创建一个新的对象。
具体使用
//初始化一个sync.Pool并且指定创建对象的方法
pool := &sync.Pool{
New:func() interface{} {
return 0
},
}
arry := pool.Get().(int) //这里面还需要进行断言一下判断一下
//...
pool.Put(10)
为什么称sync.Pool为缓存
- GC会清除sync.Pool缓存的对象
- 对象的缓存有效期为下一次GC之前,不利于保存连接