pool.go 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package syncx
  2. import (
  3. "sync"
  4. "time"
  5. "github.com/tal-tech/go-zero/core/timex"
  6. )
  7. type (
  8. PoolOption func(*Pool)
  9. node struct {
  10. item interface{}
  11. next *node
  12. lastUsed time.Duration
  13. }
  14. Pool struct {
  15. limit int
  16. created int
  17. maxAge time.Duration
  18. lock sync.Locker
  19. cond *sync.Cond
  20. head *node
  21. create func() interface{}
  22. destroy func(interface{})
  23. }
  24. )
  25. func NewPool(n int, create func() interface{}, destroy func(interface{}), opts ...PoolOption) *Pool {
  26. if n <= 0 {
  27. panic("pool size can't be negative or zero")
  28. }
  29. lock := new(sync.Mutex)
  30. pool := &Pool{
  31. limit: n,
  32. lock: lock,
  33. cond: sync.NewCond(lock),
  34. create: create,
  35. destroy: destroy,
  36. }
  37. for _, opt := range opts {
  38. opt(pool)
  39. }
  40. return pool
  41. }
  42. func (p *Pool) Get() interface{} {
  43. p.lock.Lock()
  44. defer p.lock.Unlock()
  45. for {
  46. if p.head != nil {
  47. head := p.head
  48. p.head = head.next
  49. if p.maxAge > 0 && head.lastUsed+p.maxAge < timex.Now() {
  50. p.created--
  51. p.destroy(head.item)
  52. continue
  53. } else {
  54. return head.item
  55. }
  56. }
  57. if p.created < p.limit {
  58. p.created++
  59. return p.create()
  60. }
  61. p.cond.Wait()
  62. }
  63. }
  64. func (p *Pool) Put(x interface{}) {
  65. if x == nil {
  66. return
  67. }
  68. p.lock.Lock()
  69. defer p.lock.Unlock()
  70. p.head = &node{
  71. item: x,
  72. next: p.head,
  73. lastUsed: timex.Now(),
  74. }
  75. p.cond.Signal()
  76. }
  77. func WithMaxAge(duration time.Duration) PoolOption {
  78. return func(pool *Pool) {
  79. pool.maxAge = duration
  80. }
  81. }