Go实现资源池

--------------------------------------pool.go----------------------------------------------

package pool

import (
   "sync"
   "io"
   "errors"
   "log"
)

var (
   ErrSizeTooSmall = errors.New("池大小必须为正整数")
   ErrPoolClosed   = errors.New("池已关闭")
)

//Pool 管理一组可以安全地在多个goroutine间共享的资源,被管理资源必须实现io.Closer接口
type Pool struct {
   m         sync.Mutex
   resources chan io.Closer
   factory   func() (io.Closer, error)
   closed    bool
}

//New 创建一个新池,并限定池大小,并需要一个创建资源的工厂函数
func New(size int, factory func() (io.Closer, error)) (*Pool, error) {
   if size < 1 {
      return nil, ErrSizeTooSmall
   }
   return &Pool{
      factory:   factory,
      resources: make(chan io.Closer, size),
      closed:    false,
   }, nil
}

//Acquire 从池中获取一个资源
func (p *Pool) Acquire() (io.Closer, error) {
   select {
   // 检查池中是否有空闲资源,如果不ok,则说明池已关闭
   case r, ok := <-p.resources:
      log.Println("Acquire:", "Shared Resource")
      if !ok {
         return nil, ErrPoolClosed
      }
      return r, nil
      // 池中取不到的时候,新建一个
   default:
      log.Println("Acquired", "New Resource")
      return p.factory()
   }
}

// Release 将一个使用完的资源放回池里
func (p *Pool) Release(r io.Closer) {
   // 保证本操作和Release操作的安全
   p.m.Lock()
   defer p.m.Unlock()

   // 如果池已关闭,销毁资源
   if p.closed {
      r.Close()
      return
   }
   select {
   // 尝试将资源放回队列
   case p.resources <- r:
      log.Println("Releaser:", "In Queue")
   // 如果队列已满,关闭这个资源
   default:
      log.Println("Release:", "Closing")
      r.Close()
   }
}

// Close 关闭池,并关闭池的所有资源
func (p *Pool) Close() {
   // 保证本操作与Release操作的安全
   p.m.Lock()
   defer p.m.Unlock()

   // pool已关闭,什么也不做
   if p.closed {
      return
   }
   // 标记池已关闭
   p.closed = true
   // 清空chan之前需要先关闭,否则会发生死锁
   close(p.resources)
   // 关闭资源
   for r := range p.resources {
      r.Close()
   }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章