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实战》