Go对象池

对象池是经常会用到的一个功能,使用 buffer channel 实现

package obj_pool

import (
        "errors"
        "time"
)

type ReusableObj struct{}

type ObjPool struct {
        bufChan chan *ReusableObj // 用于缓冲可重用对象
}

func NewObjPool(numOfObj int) *ObjPool {
        ObjPool := ObjPool{}
        ObjPool.bufChan = make(chan *ReusableObj, numOfObj) // numOfObj 表示迟的大小
        for i := 0; i < numOfObj; i++ {
                ObjPool.bufChan <- &ReusableObj{}
        }
        return &ObjPool
}

func (p *ObjPool) GetObj(timeout time.Duration) (*ReusableObj, error) {
        select {
        case ret := <-p.bufChan:
                return ret, nil
        case <-time.After(timeout): // 超时控制
                return nil, errors.New("time out")
        }
}

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

下面是针对上面代码的测试程序

package obj_pool

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

func TestObjPool(t *testing.T) {
        pool := NewObjPool(10)
        // 测试 overflow
        //if err := pool.ReleaseObj(&ReusableObj{}); err != nil{
        //      t.Error(err)
        //}
        for i := 0; i < 11; i++ {
                if v, err := pool.GetObj(time.Second * 1); err != nil {
                        t.Error(err)
                } else {
                        fmt.Printf("%T\n", v)
                        if err := pool.ReleaseObj(v); err != nil {
                                t.Error(err)
                        }
                }
        }
        fmt.Println("Done!")
}

对象池适用于复杂难于创建的对象,对于简单容易创建的对象不适用。