go 用channel实现对象池并且与sync.Pool对比

标题对象池的实现

原料

  • 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
}

实现思路

  1. 在初始化的时候,按照指示将对象放入有buffer的chan里面存储
  2. get的时候就从chan里面获取一个对象返回,并且设置超时时间,如果超过时间没有其他的人去释放就会返回超时错误。
  3. 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之前,不利于保存连接

你可能感兴趣的:(go)