pool.go 1.8 KB

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