github.com/zhongdalu/gf@v1.0.0/g/container/gpool/gpool.go (about) 1 // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/zhongdalu/gf. 6 7 // Package gpool provides object-reusable concurrent-safe pool. 8 package gpool 9 10 import ( 11 "errors" 12 "time" 13 14 "github.com/zhongdalu/gf/g/container/glist" 15 "github.com/zhongdalu/gf/g/container/gtype" 16 "github.com/zhongdalu/gf/g/os/gtime" 17 "github.com/zhongdalu/gf/g/os/gtimer" 18 ) 19 20 // Object-Reusable Pool. 21 type Pool struct { 22 list *glist.List // Available/idle list. 23 closed *gtype.Bool // Whether the pool is closed. 24 Expire int64 // Max idle time(ms), after which it is recycled. 25 NewFunc func() (interface{}, error) // Callback function to create item. 26 ExpireFunc func(interface{}) // Expired destruction function for objects. 27 // This function needs to be defined when the pool object 28 // needs to perform additional destruction operations. 29 // Eg: net.Conn, os.File, etc. 30 } 31 32 // Pool item. 33 type poolItem struct { 34 expire int64 // Expire time(millisecond). 35 value interface{} // Value. 36 } 37 38 // Creation function for object. 39 type NewFunc func() (interface{}, error) 40 41 // Destruction function for object. 42 type ExpireFunc func(interface{}) 43 44 // New returns a new object pool. 45 // To ensure execution efficiency, the expiration time cannot be modified once it is set. 46 // 47 // Expiration logistics: 48 // expire = 0 : not expired; 49 // expire < 0 : immediate expired after use; 50 // expire > 0 : timeout expired; 51 // Note that the expiration time unit is ** milliseconds **. 52 func New(expire int, newFunc NewFunc, expireFunc ...ExpireFunc) *Pool { 53 r := &Pool{ 54 list: glist.New(), 55 closed: gtype.NewBool(), 56 Expire: int64(expire), 57 NewFunc: newFunc, 58 } 59 if len(expireFunc) > 0 { 60 r.ExpireFunc = expireFunc[0] 61 } 62 gtimer.AddSingleton(time.Second, r.checkExpire) 63 return r 64 } 65 66 // Put puts an item to pool. 67 func (p *Pool) Put(value interface{}) { 68 item := &poolItem{ 69 value: value, 70 } 71 if p.Expire == 0 { 72 item.expire = 0 73 } else { 74 item.expire = gtime.Millisecond() + p.Expire 75 } 76 p.list.PushBack(item) 77 } 78 79 // Clear clears pool, which means it will remove all items from pool. 80 func (p *Pool) Clear() { 81 p.list.RemoveAll() 82 } 83 84 // Get picks an item from pool. 85 func (p *Pool) Get() (interface{}, error) { 86 for !p.closed.Val() { 87 if r := p.list.PopFront(); r != nil { 88 f := r.(*poolItem) 89 if f.expire == 0 || f.expire > gtime.Millisecond() { 90 return f.value, nil 91 } 92 } else { 93 break 94 } 95 } 96 if p.NewFunc != nil { 97 return p.NewFunc() 98 } 99 return nil, errors.New("pool is empty") 100 } 101 102 // Size returns the count of available items of pool. 103 func (p *Pool) Size() int { 104 return p.list.Len() 105 } 106 107 // Close closes the pool. If <p> has ExpireFunc, 108 // then it automatically closes all items using this function before it's closed. 109 func (p *Pool) Close() { 110 p.closed.Set(true) 111 } 112 113 // checkExpire removes expired items from pool every second. 114 func (p *Pool) checkExpire() { 115 if p.closed.Val() { 116 // If p has ExpireFunc, 117 // then it must close all items using this function. 118 if p.ExpireFunc != nil { 119 for { 120 if r := p.list.PopFront(); r != nil { 121 p.ExpireFunc(r.(*poolItem).value) 122 } else { 123 break 124 } 125 } 126 } 127 gtimer.Exit() 128 } 129 for { 130 // TODO Do not use Pop and Push mechanism, which is not graceful. 131 if r := p.list.PopFront(); r != nil { 132 item := r.(*poolItem) 133 if item.expire == 0 || item.expire > gtime.Millisecond() { 134 p.list.PushFront(item) 135 break 136 } 137 if p.ExpireFunc != nil { 138 p.ExpireFunc(item.value) 139 } 140 } else { 141 break 142 } 143 } 144 }