github.com/suiyunonghen/dxcommonlib@v0.0.0-20190612012041-7f8547a81a67/TimeWheelingWorker.go (about) 1 /* 2 时间轮询调度池,只用一个定时器来实现After等超时设定,默认轮渡器设定为1个小时,精度为500毫秒 3 如果要使用更精确的定时器,请使用NewTimeWheelWorker自己指定定时器时间,目前在我的电脑上测试来看,最精确能到2毫秒 4 Autor: 不得闲 5 QQ:75492895 6 */ 7 package DxCommonLib 8 9 import ( 10 "sync" 11 "sync/atomic" 12 "time" 13 ) 14 15 type ( 16 17 //每个槽中的记录对象 18 slotRecord struct { 19 curWheelIndex int //当前轮询的索引 20 wheelCount int //需要轮询多少次触发 21 notifychan chan struct{} //通知 22 next *slotRecord //下一个轮询点 23 } 24 25 TimeWheelWorker struct { 26 sync.Mutex //调度锁 27 ticker *time.Ticker //调度器时钟 28 timeslocks []*slotRecord //时间槽 29 slockcount int 30 maxTimeout time.Duration 31 quitchan chan struct{} 32 curindex int //当前的索引 33 interval time.Duration 34 tkfunc func() 35 recordPool sync.Pool 36 } 37 ) 38 39 40 var ( 41 defaultTimeWheelWorker *TimeWheelWorker 42 coarseTime atomic.Value //存放的是当前的实际时间 43 ) 44 45 //interval指定调度的时间间隔 46 //slotBlockCount指定时间轮的块长度 47 func NewTimeWheelWorker(interval time.Duration, slotBlockCount int,tkfunc func()) *TimeWheelWorker { 48 result := new(TimeWheelWorker) 49 result.interval = interval 50 result.quitchan = make(chan struct{}) 51 result.slockcount = slotBlockCount 52 result.tkfunc = tkfunc 53 result.maxTimeout = interval * time.Duration(slotBlockCount) 54 result.timeslocks = make([]*slotRecord, slotBlockCount) 55 result.ticker = time.NewTicker(interval) 56 go result.run() 57 return result 58 } 59 60 func (worker *TimeWheelWorker) run() { 61 for { 62 select { 63 case <-worker.ticker.C: 64 //执行定时操作 65 //获取当前的时间槽数据 66 worker.Lock() 67 lastrec := worker.timeslocks[worker.curindex] 68 if lastrec != nil{ 69 var firstrec *slotRecord 70 for{ 71 currec := lastrec.next 72 lastrec.curWheelIndex++ 73 if lastrec.curWheelIndex >= lastrec.wheelCount{ //断开 74 worker.freeRecord(lastrec) 75 }else if firstrec == nil{ 76 firstrec = lastrec //插入的时候就直接按照wheelCount大小排序了,只用增加一个个的序号就行了 77 for currec != nil{ 78 currec.curWheelIndex++ 79 currec = currec.next 80 } 81 break 82 }/*else{ 83 firstrec.next = lastrec 84 }*/ 85 if currec == nil{ 86 break 87 } 88 lastrec = currec 89 } 90 worker.timeslocks[worker.curindex] = firstrec 91 } 92 worker.curindex = (worker.curindex + 1) % worker.slockcount 93 worker.Unlock() 94 if worker.tkfunc!=nil{ 95 worker.tkfunc() 96 } 97 case <-worker.quitchan: 98 worker.ticker.Stop() 99 return 100 } 101 } 102 } 103 104 func (worker *TimeWheelWorker) Stop() { 105 close(worker.quitchan) 106 } 107 108 func (worker *TimeWheelWorker)getRecord(wheelcount int)*slotRecord { 109 var result *slotRecord 110 v := worker.recordPool.Get() 111 if v!=nil{ 112 result = v.(*slotRecord) 113 }else{ 114 result = new(slotRecord) 115 } 116 result.curWheelIndex = 0 117 result.wheelCount = wheelcount 118 result.notifychan = make(chan struct{}) 119 result.next = nil 120 return result 121 } 122 123 func (worker *TimeWheelWorker)freeRecord(rec *slotRecord) { 124 rec.next = nil 125 close(rec.notifychan) 126 rec.notifychan = nil 127 rec.wheelCount = 0 128 rec.curWheelIndex = 0 129 worker.recordPool.Put(rec) 130 } 131 132 func (worker *TimeWheelWorker) After(d time.Duration) <-chan struct{} { 133 index := int(d / worker.interval) //触发多少次到 134 wheelcount := int(index / worker.slockcount) 135 if index % worker.slockcount > 0{ 136 wheelcount++ 137 } 138 if index > 0 { 139 index-- 140 } 141 worker.Lock() 142 index = (worker.curindex + index) % worker.slockcount 143 rec := worker.timeslocks[index] 144 if rec == nil { 145 rec = worker.getRecord(wheelcount) 146 worker.timeslocks[index] = rec 147 }else{ //查找对应的位置 148 var last *slotRecord=nil 149 for{ 150 currec := rec.next 151 if wheelcount < rec.wheelCount{ 152 currec = worker.getRecord(wheelcount) 153 currec.next = rec 154 if last == nil{ 155 worker.timeslocks[index] = currec 156 }else{ 157 last.next = currec 158 } 159 rec = currec 160 break 161 }else if wheelcount == rec.wheelCount{ //已经存在,直接退出 162 break 163 }else if currec == nil{ 164 currec = worker.getRecord(wheelcount) //链接一个新的 165 rec.next = currec 166 rec = currec 167 break 168 } 169 last = rec 170 rec = currec 171 } 172 } 173 worker.Unlock() 174 return rec.notifychan 175 } 176 177 func (worker *TimeWheelWorker)AfterFunc(d time.Duration,afunc func()) { 178 select{ 179 case <-worker.After(d): 180 afunc() 181 } 182 } 183 184 func (worker *TimeWheelWorker) Sleep(d time.Duration) { 185 select{ 186 case <-worker.After(d): 187 return 188 } 189 } 190 191 func After(d time.Duration) <-chan struct{} { 192 return defaultTimeWheelWorker.After(d) 193 } 194 195 func AfterFunc(d time.Duration,afunc func()) { 196 defaultTimeWheelWorker.AfterFunc(d,afunc) 197 } 198 199 func Sleep(d time.Duration) { 200 defaultTimeWheelWorker.Sleep(d) 201 } 202 203 func ReSetDefaultTimeWheel(Chkinterval time.Duration,slotBlockCount int){ 204 if defaultTimeWheelWorker.interval != Chkinterval || 205 defaultTimeWheelWorker.slockcount != slotBlockCount{ 206 defaultTimeWheelWorker.Stop() 207 defaultTimeWheelWorker = NewTimeWheelWorker(Chkinterval, slotBlockCount, func() { 208 t := time.Now().Truncate(Chkinterval) 209 coarseTime.Store(&t) 210 }) 211 } 212 } 213 214 215 func init() { 216 defaultTimeWheelWorker = NewTimeWheelWorker(time.Millisecond*500, 7200, func() { 217 t := time.Now().Truncate(time.Millisecond*500) 218 coarseTime.Store(&t) 219 }) 220 t := time.Now().Truncate(time.Millisecond*500) 221 coarseTime.Store(&t) 222 } 223 224 func CoarseTimeNow() time.Time { 225 tp := coarseTime.Load().(*time.Time) 226 return *tp 227 } 228