github.com/geniusesgroup/libgo@v0.0.0-20220713101832-828057a9d3d4/timer/timing-wheel.go (about) 1 /* For license and copyright information please see LEGAL file in repository */ 2 3 package timer 4 5 import ( 6 "../protocol" 7 ) 8 9 type TimingWheel struct { 10 wheel [][]*Timer 11 interval protocol.Duration // same as tw.ticker.period 12 pos int 13 ticker Timer 14 stop chan struct{} 15 } 16 17 // if you make one sec interval for a earth day(60*60*24=86400), you need 2MB ram just to hold empty wheel without any timer. 18 func (tw *TimingWheel) Init(interval protocol.Duration, wheelSize int) { 19 tw.stop = make(chan struct{}) 20 tw.wheel = make([][]*Timer, wheelSize) 21 tw.ticker.Init(nil, nil) 22 tw.interval = interval 23 } 24 25 func (tw *TimingWheel) AddTimer(t *Timer) { 26 var addedPosition = tw.addedPosition(t) 27 if addedPosition == tw.pos { 28 // TODO::: run the timer?? 29 return 30 } 31 tw.wheel[addedPosition] = append(tw.wheel[addedPosition], t) 32 } 33 34 // call by go keyword if you don't want the current goroutine block. 35 func (tw *TimingWheel) Start() { 36 tw.ticker.Tick(tw.interval, tw.interval, -1) 37 LOOP: 38 for { 39 select { 40 case <-tw.ticker.Signal(): 41 var pos = tw.pos 42 tw.incrementTickPosition() 43 var timers = tw.wheel[pos] 44 tw.wheel[pos] = timers[:0] 45 for i := 0; i < len(timers); i++ { 46 var timer = timers[i] 47 timer.callback(timer.arg) 48 tw.checkAndAddTimerAgain(timer) 49 } 50 case <-tw.stop: 51 tw.stop = nil 52 break LOOP 53 } 54 } 55 tw.ticker.Stop() 56 } 57 58 // Not concurrent safe. 59 func (tw *TimingWheel) Stop() (alreadyStopped bool) { 60 if tw.stop == nil { 61 return true 62 } 63 64 select { 65 case tw.stop <- struct{}{}: 66 default: 67 alreadyStopped = true 68 } 69 tw.ticker.Stop() 70 return 71 } 72 73 func (tw *TimingWheel) incrementTickPosition() { 74 var wheelLen = len(tw.wheel) 75 if wheelLen-1 == tw.pos { 76 tw.pos = 0 77 } else { 78 tw.pos++ 79 } 80 } 81 82 func (tw *TimingWheel) checkAndAddTimerAgain(t *Timer) { 83 if t.periodNumber == 0 { 84 t.reset() 85 } else { 86 var addedPosition = tw.addedPosition(t) 87 tw.wheel[addedPosition] = append(tw.wheel[addedPosition], t) 88 if t.periodNumber > 0 { 89 t.periodNumber-- 90 } 91 } 92 } 93 94 func (tw *TimingWheel) addedPosition(t *Timer) int { 95 return int(t.period/tw.interval) + tw.pos 96 }