go语言学习笔记——对象池

333 阅读2分钟

对象池在大家平时的工作中也是经常遇见的,尤其是创建代价笔记高的对象,比如数据库的链接,经常会用到对象池,避免重复创建。

微信截图_20220202134734.png

在go语言中,可以使用buffer channel实现一个对象池。

初始化对象池

首先,预设一个对象池的数据结构

type ResourcePool struct {
}

type ObjPool struct {
   bufChan chan *ResourcePool
}

然后初始化对象池里面的对象,用来使用。 初始化一个buffer channel,通过外部的配置,用来控制buffer的长度,然后把对应的空对象写入channel里面。

func NewObjPool(numObj int) *ObjPool {
   objPool := ObjPool{}
   objPool.bufChan = make(chan *ResourcePool, numObj)
   for i := 0; i < numObj; i++ {
      objPool.bufChan <- &ResourcePool{}
   }
   return &objPool
}

从对象池获取对象

对象池初始化完成之后,外部需要在对象池,获取对象。

使用select,用来用来消费buffer channel里面的对象。

func (p *ObjPool) GetObj(timeout time.Duration) (*ResourcePool, error) {
   select {
   case ret := <-p.bufChan:
      return ret, nil
   case <-time.After(timeout):
      return nil, errors.New("timeout")
   }
}

释放对象

在对应的对象使用完成之后,我们需要再把对象释放掉,重新写入到对象池中


func (p *ObjPool) ReleaseObj(obj *ResourcePool) error {
   select {
   case p.bufChan <- obj:
      return nil
   default:
      return errors.New("overflow")
   }
}

测试函数

我们简单写个测试函数,进行一个测试

func TestObjPool(t *testing.T) {
   pool := NewObjPool(10)
   for i := 0; i < 11; i++ {
      if v, err := pool.GetObj(time.Second * 1); err != nil {
         t.Error(err)
      } else {
         t.Logf("get obj: %p", v)
         if err := pool.ReleaseObj(v); err != nil {
            t.Error(err)
         }
      }

   }
   fmt.Println("Done")
}

输出

=== RUN   TestObjPool
    obj_pool_test.go:57: get obj: 0xa637e8
    obj_pool_test.go:57: get obj: 0xa637e8
    obj_pool_test.go:57: get obj: 0xa637e8
    obj_pool_test.go:57: get obj: 0xa637e8
    obj_pool_test.go:57: get obj: 0xa637e8
    obj_pool_test.go:57: get obj: 0xa637e8
    obj_pool_test.go:57: get obj: 0xa637e8
    obj_pool_test.go:57: get obj: 0xa637e8
    obj_pool_test.go:57: get obj: 0xa637e8
    obj_pool_test.go:57: get obj: 0xa637e8
    obj_pool_test.go:57: get obj: 0xa637e8
Done
--- PASS: TestObjPool (0.00s)
PASS

完整代码

package Class33

import (
   "errors"
   "fmt"
   "testing"
   "time"
)

type ResourcePool struct {
}

type ObjPool struct {
   bufChan chan *ResourcePool
}

func NewObjPool(numObj int) *ObjPool {
   objPool := ObjPool{}
   objPool.bufChan = make(chan *ResourcePool, numObj)
   for i := 0; i < numObj; i++ {
      objPool.bufChan <- &ResourcePool{}
   }
   return &objPool
}

func (p *ObjPool) GetObj(timeout time.Duration) (*ResourcePool, error) {
   select {
   case ret := <-p.bufChan:
      return ret, nil
   case <-time.After(timeout):
      return nil, errors.New("timeout")
   }
}

func (p *ObjPool) ReleaseObj(obj *ResourcePool) error {
   select {
   case p.bufChan <- obj:
      return nil
   default:
      return errors.New("overflow")
   }
}

func TestObjPool(t *testing.T) {
   pool := NewObjPool(10)
   for i := 0; i < 11; i++ {
      if v, err := pool.GetObj(time.Second * 1); err != nil {
         t.Error(err)
      } else {
         t.Logf("get obj: %p", v)
         if err := pool.ReleaseObj(v); err != nil {
            t.Error(err)
         }
      }

   }
   fmt.Println("Done")
}