github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/cache/cache.go (about) 1 package cache 2 3 import ( 4 "runtime" 5 "sync" 6 "time" 7 ) 8 9 type Cache struct { 10 defaultExpiration time.Duration 11 items map[string]Item 12 mu sync.RWMutex 13 onEvicted func(string, any) 14 j *janitor 15 } 16 17 type Item struct { 18 //data 19 Data any 20 //ttl time.UnixNano.Expiration of Item,if it is -1,it will be not Expired 21 Ttl int64 22 } 23 24 func (item *Item) Expired() bool { 25 if item.Ttl == -1 { 26 //用户 27 return false 28 } 29 return time.Now().UnixNano() > item.Ttl 30 } 31 32 func New() *Cache { 33 return NewWithExpiration(0) 34 } 35 36 func NewWithExpiration(expiration time.Duration) *Cache { 37 return NewWithExpirationAndCleanupInterval(expiration, 0) 38 } 39 40 func NewWithCleanupInterval(cleanupInterval time.Duration) *Cache { 41 return NewWithExpirationAndCleanupInterval(0, cleanupInterval) 42 } 43 func NewWithExpirationAndCleanupInterval(defaultExpiration, cleanupInterval time.Duration) *Cache { 44 if defaultExpiration == 0 { 45 defaultExpiration = -1 46 } 47 ch := make(chan bool) 48 c := &Cache{ 49 defaultExpiration: defaultExpiration, 50 items: make(map[string]Item), 51 j: &janitor{ 52 Interval: 1 * time.Second, 53 stop: ch, 54 }, 55 } 56 //启动清理协程 57 go func() { 58 c.runCleanup(cleanupInterval) 59 runtime.SetFinalizer(c, stopJanitor) 60 }() 61 return c 62 } 63 64 type janitor struct { 65 Interval time.Duration 66 stop chan bool 67 } 68 69 func (c *Cache) runCleanup(cleanupInterval time.Duration) { 70 if cleanupInterval == 0 { 71 cleanupInterval = 500 * time.Millisecond 72 } 73 ticker := time.NewTicker(cleanupInterval) 74 for { 75 select { 76 case <-ticker.C: 77 c.DeleteExpired() 78 case <-c.j.stop: 79 ticker.Stop() 80 return 81 } 82 } 83 } 84 85 func stopJanitor(c *Cache) { 86 c.j.stop <- true 87 } 88 89 func (c *Cache) DeleteExpired() { 90 l := len(c.items) 91 if l < 1 { 92 return 93 } 94 cloneMap := map[string]Item{} 95 c.mu.Lock() 96 for k, v := range c.items { 97 cloneMap[k] = v 98 } 99 c.mu.Unlock() 100 101 ch := make(chan int8, len(c.items)) 102 for key, item := range cloneMap { 103 go func(k string, i Item) { 104 if i.Expired() { 105 c.mu.Lock() 106 delete(c.items, k) 107 c.mu.Unlock() 108 } 109 ch <- int8(1) 110 }(key, item) 111 } 112 }