github.com/dfklegend/cell2/utils@v0.0.0-20240402033734-a0a9f3d9335d/timer/timer.go (about) 1 package timer 2 3 import ( 4 "sync" 5 "time" 6 7 "github.com/dfklegend/cell2/utils/common" 8 l "github.com/dfklegend/cell2/utils/logger" 9 ) 10 11 /** 12 * timer到期后,被push到channel 13 * 便于整合到具体使用线程 14 * 此timer性能一般,后续考虑做一个性能更好的 15 */ 16 17 type IdType uint64 18 type CBFunc func(...interface{}) 19 type QueueChan chan *Obj 20 21 var timerMgr = NewTimerMgr() 22 23 type ITimerMgr interface { 24 After(duration time.Duration, cb CBFunc, args ...interface{}) IdType 25 AddTimer(duration time.Duration, cb func(), args ...interface{}) IdType 26 Cancel(id IdType) 27 GetQueue() QueueChan 28 } 29 30 type Obj struct { 31 TimerId IdType 32 Duration time.Duration 33 CB CBFunc 34 Args []interface{} 35 Canceled bool 36 timer *time.Timer 37 } 38 39 // NewTimerObj TODO: 可以考虑pool 40 func NewTimerObj(id IdType, 41 duration time.Duration, 42 cb CBFunc, 43 args []interface{}) *Obj { 44 return &Obj{ 45 TimerId: id, 46 Duration: duration, 47 CB: cb, 48 Args: args, 49 Canceled: false, 50 } 51 } 52 53 // Mgr 每个环境可以创建自己的timerMgr 54 type Mgr struct { 55 idService *common.SerialIdService64 56 queue QueueChan 57 58 // 用于cancel 59 // TimerIdType:*TimerObj 60 timers sync.Map 61 running bool 62 } 63 64 func NewTimerMgr() *Mgr { 65 return &Mgr{ 66 idService: common.NewSerialIdService64(), 67 queue: make(QueueChan, 999), 68 running: true, 69 } 70 } 71 72 // 用于简单测试 73 // 用户可以创建自己的 74 func GetTimerMgr() *Mgr { 75 return timerMgr 76 } 77 78 func (m *Mgr) Stop() { 79 m.running = false 80 } 81 82 func (m *Mgr) allocId() IdType { 83 return IdType(m.idService.AllocId()) 84 } 85 86 func (m *Mgr) After(duration time.Duration, cb CBFunc, args ...interface{}) IdType { 87 t := NewTimerObj(m.allocId(), 88 0, cb, args) 89 90 m.doLater(duration, t) 91 m.timers.Store(t.TimerId, t) 92 return t.TimerId 93 } 94 95 func (m *Mgr) AddTimer(duration time.Duration, cb CBFunc, args ...interface{}) IdType { 96 t := NewTimerObj(m.allocId(), 97 duration, cb, args) 98 99 m.doLater(duration, t) 100 m.timers.Store(t.TimerId, t) 101 return t.TimerId 102 } 103 104 func (m *Mgr) Cancel(id IdType) { 105 v, ok := m.timers.Load(id) 106 if !ok { 107 return 108 } 109 t := v.(*Obj) 110 t.Canceled = true 111 if t.timer != nil { 112 t.timer.Stop() 113 } 114 115 m.timers.Delete(id) 116 } 117 118 func (m *Mgr) doLater(duration time.Duration, t *Obj) { 119 t.timer = time.AfterFunc(duration, func() { 120 //log.Println("cb") 121 if t.Canceled { 122 return 123 } 124 125 // 停止了 126 if !m.running { 127 return 128 } 129 // 底层在新routine执行 130 // time.AfterFunc 131 m.queue <- t 132 }) 133 } 134 135 /* 136 select { 137 case t :<- mgr.GetQueue(): 138 mgr.Do(t) 139 } 140 */ 141 // 外部从queue读取后,调用 142 func (m *Mgr) Do(t *Obj) { 143 if t.Canceled { 144 return 145 } 146 147 //t.CB(t.Args...) 148 m.do(t) 149 150 // CB内被cancel掉了 151 if t.Canceled { 152 return 153 } 154 155 if t.Duration > 0 { 156 m.doLater(t.Duration, t) 157 } else { 158 m.timers.Delete(t.TimerId) 159 } 160 } 161 162 func (m *Mgr) do(t *Obj) { 163 defer func() { 164 if err := recover(); err != nil { 165 l.E.Errorf("panic in timer.do:%v", err) 166 l.E.Errorf(common.GetStackStr()) 167 } 168 }() 169 170 t.CB(t.Args...) 171 } 172 173 func (m *Mgr) GetQueue() QueueChan { 174 return m.queue 175 }