Go 利用 buffer channel 做一个资源池
Go可以利用buffer channel做一个资源池,channel中元素是资源类型,比如实现io.Closer的资源。
资源池要有哪几个功能?
- 创建一个池
- 从池中取一个资源
- 释放某个资源回池里
- 关闭资源池
池的结构
- 创建一个资源的函数可以放在池结构里,当池内没有资源时创建
- 关闭状态
- 缓冲池
- 一把锁
代码
package pool
import (
"errors"
"io"
"log"
"sync"
)
type Pool struct {
m sync.Mutex
closed bool
resources chan io.Closer
fn func() (io.Closer, error)
}
// 传入创建一个资源的函数,池大小
func New(fn func() (io.Closer, error), size uint) (*Pool, error) {
if size <= 0 {
return nil, errors.New("size not right")
}
return &Pool{
resources: make(chan io.Closer, size),
fn: fn,
}, nil
}
func (p *Pool) Acquire() (io.Closer, error) {
select {
case r, ok := <-p.resources:
log.Println("Acquire one exist resource")
if !ok {
return nil, errors.New("closed")
}
return r, nil
default:
// 池内没有资源,需要创建一个
log.Println("create one resource")
return p.fn()
}
}
func (p *Pool) Release(r io.Closer) {
// 读取p.closed,Close()中有写p.close,避免多goroutine竞争,需要上锁
p.m.Lock()
defer p.m.Unlock()
if p.closed {
r.Close()
return
}
select {
case p.resources <- r: // 放回池里
log.Println("put in ")
default:
// 池已经满了,需要关闭当前资源
r.Close()
log.Println("full close self ")
}
return
}
func (p *Pool) Close() {
p.m.Lock()
defer p.m.Unlock()
if p.closed {
return
}
p.closed = true
// range channel时关闭channel
close(p.resources)
// 关闭池内所有资源
for r := range p.resources {
r.Close()
}
return
}
参考:
《Go实战》