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()
   }
}

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