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

本文介绍了如何使用Go语言的channel实现对象池,并与内置的sync.Pool进行对比。通过初始化时将对象放入带有缓冲的channel中,get操作时设置超时并确保对象的有效性,release操作时考虑channel的容量限制。同时,文章讨论了sync.Pool的内部结构,包括每个处理器的私有对象和共享池,以及在不同情况下的对象获取策略。最后,强调了sync.Pool被称作缓存的原因,即在GC期间可能会清除其中的对象,导致对象的缓存有效期受限。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

标题对象池的实现

原料

  • 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之前,不利于保存连接
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值