github.com/lingyao2333/mo-zero@v1.4.1/core/syncx/pool.go (about)

     1  package syncx
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	"github.com/lingyao2333/mo-zero/core/timex"
     8  )
     9  
    10  type (
    11  	// PoolOption defines the method to customize a Pool.
    12  	PoolOption func(*Pool)
    13  
    14  	node struct {
    15  		item     interface{}
    16  		next     *node
    17  		lastUsed time.Duration
    18  	}
    19  
    20  	// A Pool is used to pool resources.
    21  	// The difference between sync.Pool is that:
    22  	//  1. the limit of the resources
    23  	//  2. max age of the resources can be set
    24  	//  3. the method to destroy resources can be customized
    25  	Pool struct {
    26  		limit   int
    27  		created int
    28  		maxAge  time.Duration
    29  		lock    sync.Locker
    30  		cond    *sync.Cond
    31  		head    *node
    32  		create  func() interface{}
    33  		destroy func(interface{})
    34  	}
    35  )
    36  
    37  // NewPool returns a Pool.
    38  func NewPool(n int, create func() interface{}, destroy func(interface{}), opts ...PoolOption) *Pool {
    39  	if n <= 0 {
    40  		panic("pool size can't be negative or zero")
    41  	}
    42  
    43  	lock := new(sync.Mutex)
    44  	pool := &Pool{
    45  		limit:   n,
    46  		lock:    lock,
    47  		cond:    sync.NewCond(lock),
    48  		create:  create,
    49  		destroy: destroy,
    50  	}
    51  
    52  	for _, opt := range opts {
    53  		opt(pool)
    54  	}
    55  
    56  	return pool
    57  }
    58  
    59  // Get gets a resource.
    60  func (p *Pool) Get() interface{} {
    61  	p.lock.Lock()
    62  	defer p.lock.Unlock()
    63  
    64  	for {
    65  		if p.head != nil {
    66  			head := p.head
    67  			p.head = head.next
    68  			if p.maxAge > 0 && head.lastUsed+p.maxAge < timex.Now() {
    69  				p.created--
    70  				p.destroy(head.item)
    71  				continue
    72  			} else {
    73  				return head.item
    74  			}
    75  		}
    76  
    77  		if p.created < p.limit {
    78  			p.created++
    79  			return p.create()
    80  		}
    81  
    82  		p.cond.Wait()
    83  	}
    84  }
    85  
    86  // Put puts a resource back.
    87  func (p *Pool) Put(x interface{}) {
    88  	if x == nil {
    89  		return
    90  	}
    91  
    92  	p.lock.Lock()
    93  	defer p.lock.Unlock()
    94  
    95  	p.head = &node{
    96  		item:     x,
    97  		next:     p.head,
    98  		lastUsed: timex.Now(),
    99  	}
   100  	p.cond.Signal()
   101  }
   102  
   103  // WithMaxAge returns a function to customize a Pool with given max age.
   104  func WithMaxAge(duration time.Duration) PoolOption {
   105  	return func(pool *Pool) {
   106  		pool.maxAge = duration
   107  	}
   108  }