func (w *TimerWheel) Stop() {
	w.once.Do(func() {
		w.enable.Store(false)
		w.ticker.Stop()
	})
}
Stop stops the ticker
package gxtime
import (
	"container/list"
	"errors"
	"log"
	"sync"
	"sync/atomic"
	"time"
)
import (
	uatomic "go.uber.org/atomic"
)
var (
	ErrTimeChannelFull = errors.New("timer channel full")
	ErrTimeChannelClosed = errors.New("timer channel closed")
)
func InitDefaultTimerWheel() {
	defaultTimerWheelOnce.Do(func() {
		defaultTimerWheel = NewTimerWheel()
	})
}
func GetDefaultTimerWheel() *TimerWheel {
	return defaultTimerWheel
}
func Now() time.Time {
	return defaultTimerWheel.Now()
}
var (
	defaultTimerWheelOnce sync.Once
	defaultTimerWheel     *TimerWheel
	nextID                TimerID
	curGxTime             = time.Now().UnixNano()  
)
const (
	maxMS     = 1000
	maxSecond = 60
	maxMinute = 60
	maxHour   = 24
	maxDay    = 31
	minTickerInterval = 10e6
	maxTimerLevel     = 5
)
func msNum(expire int64) int64     { return expire / int64(time.Millisecond) }
func secondNum(expire int64) int64 { return expire / int64(time.Minute) }
func minuteNum(expire int64) int64 { return expire / int64(time.Minute) }
func hourNum(expire int64) int64   { return expire / int64(time.Hour) }
func dayNum(expire int64) int64    { return expire / (maxHour * int64(time.Hour)) }
type TimerFunc func(ID TimerID, expire time.Time, arg interface{}) error
type TimerID = uint64
type timerNode struct {
	ID       TimerID      
	trig     int64        
	typ      TimerType    
	period   int64        
	timerRun TimerFunc    
	arg      interface{}  
}
func newTimerNode(f TimerFunc, typ TimerType, period int64, arg interface{}) *timerNode {
	return &timerNode{
		ID:       atomic.AddUint64(&nextID, 1),
		trig:     atomic.LoadInt64(&curGxTime) + period,
		typ:      typ,
		period:   period,
		timerRun: f,
		arg:      arg,
	}
}
func compareTimerNode(first, second *timerNode) int {
	var ret int
	if first.trig < second.trig {
		ret = -1
	} else if first.trig > second.trig {
		ret = 1
	} else {
		ret = 0
	}
	return ret
}
type timerAction = int64
const (
	TimerActionAdd   timerAction = 1
	TimerActionDel   timerAction = 2
	TimerActionReset timerAction = 3
)
type timerNodeAction struct {
	node   *timerNode
	action timerAction
}
const (
	timerNodeQueueSize = 128
)
var (
	limit   = [maxTimerLevel + 1]int64{maxMS, maxSecond, maxMinute, maxHour, maxDay}
	msLimit = [maxTimerLevel + 1]int64{
		int64(time.Millisecond),
		int64(time.Second),
		int64(time.Minute),
		int64(time.Hour),
		int64(maxHour * time.Hour),
	}
)
type TimerWheel struct {
	start  int64                      
	clock  int64                      
	number uatomic.Int64              
	hand   [maxTimerLevel]int64       
	slot   [maxTimerLevel]*list.List  
	enable uatomic.Bool           
	timerQ chan *timerNodeAction  
	once   sync.Once       
	ticker *time.Ticker    
	wg     sync.WaitGroup  
}
func NewTimerWheel() *TimerWheel {
	w := &TimerWheel{
		clock: atomic.LoadInt64(&curGxTime),
		ticker: time.NewTicker(time.Duration(minTickerInterval)),
		timerQ: make(chan *timerNodeAction, timerNodeQueueSize),
	}
	w.enable.Store(true)
	w.start = w.clock
	for i := 0; i < maxTimerLevel; i++ {
		w.slot[i] = list.New()
	}
	w.wg.Add(1)
	go func() {
		defer w.wg.Done()
		var (
			t          time.Time
			cFlag      bool
			nodeAction *timerNodeAction
			qFlag      bool
		)
	LOOP:
		for {
			if !w.enable.Load() {
				break LOOP
			}
			select {
			case t, cFlag = <-w.ticker.C:
				if !cFlag {
					break LOOP
				}
				atomic.StoreInt64(&curGxTime, t.UnixNano())
				ret := w.timerUpdate(t)
				if ret == 0 {
					w.run()
				}
			case nodeAction, qFlag = <-w.timerQ:
				if !qFlag {
					break LOOP
				}
				switch {
				case nodeAction.action == TimerActionAdd:
					w.number.Add(1)
					w.insertTimerNode(nodeAction.node)
				case nodeAction.action == TimerActionDel:
					w.number.Add(-1)
					w.deleteTimerNode(nodeAction.node)
				case nodeAction.action == TimerActionReset:
					w.resetTimerNode(nodeAction.node)
				default:
					w.number.Add(1)
					w.insertTimerNode(nodeAction.node)
				}
			}
		}
		log.Printf("the timeWheel runner exit, current timer node num:%d", w.number.Load())
	}()
	return w
}
func (w *TimerWheel) output() {
	for idx := range w.slot {
		log.Printf("print slot %d\n", idx)
	}
}
func (w *TimerWheel) TimerNumber() int {
	return int(w.number.Load())
}
func (w *TimerWheel) Now() time.Time {
	return UnixNano2Time(atomic.LoadInt64(&curGxTime))
}
func (w *TimerWheel) run() {
	var (
		clock         int64
		err           error
		node          *timerNode
		slot          *list.List
		reinsertNodes []*timerNode
	)
	slot = w.slot[0]
	clock = atomic.LoadInt64(&w.clock)
	var next *list.Element
	for e := slot.Front(); e != nil; e = next {
		node = e.Value.(*timerNode)
		if clock < node.trig {
			break
		}
		err = node.timerRun(node.ID, UnixNano2Time(clock), node.arg)
		if err == nil && node.typ == TimerLoop {
			reinsertNodes = append(reinsertNodes, node)
		} else {
			w.number.Add(-1)
		}
		next = e.Next()
		slot.Remove(e)
	}
	for _, reinsertNode := range reinsertNodes {
		reinsertNode.trig += reinsertNode.period
		w.insertTimerNode(reinsertNode)
	}
}
func (w *TimerWheel) insertSlot(idx int, node *timerNode) {
	var (
		pos  *list.Element
		slot *list.List
	)
	slot = w.slot[idx]
	for e := slot.Front(); e != nil; e = e.Next() {
		if compareTimerNode(node, e.Value.(*timerNode)) < 0 {
			pos = e
			break
		}
	}
	if pos != nil {
		slot.InsertBefore(node, pos)
	} else {
		slot.PushBack(node)
	}
}
func (w *TimerWheel) deleteTimerNode(node *timerNode) {
	var level int
LOOP:
	for level = range w.slot[:] {
		for e := w.slot[level].Front(); e != nil; e = e.Next() {
			if e.Value.(*timerNode).ID == node.ID {
				w.slot[level].Remove(e)
				break LOOP
			}
		}
	}
}
func (w *TimerWheel) resetTimerNode(node *timerNode) {
	var level int
LOOP:
	for level = range w.slot[:] {
		for e := w.slot[level].Front(); e != nil; e = e.Next() {
			if e.Value.(*timerNode).ID == node.ID {
				n := e.Value.(*timerNode)
				n.trig -= n.period
				n.period = node.period
				n.trig += n.period
				w.slot[level].Remove(e)
				w.insertTimerNode(n)
				break LOOP
			}
		}
	}
}
func (w *TimerWheel) deltaDiff(clock int64) int64 {
	var handTime int64
	for idx, hand := range w.hand[:] {
		handTime += hand * msLimit[idx]
	}
	return clock - w.start - handTime
}
func (w *TimerWheel) insertTimerNode(node *timerNode) {
	var (
		idx  int
		diff int64
	)
	diff = node.trig - atomic.LoadInt64(&w.clock)
	switch {
	case diff <= 0:
		idx = 0
	case dayNum(diff) != 0:
		idx = 4
	case hourNum(diff) != 0:
		idx = 3
	case minuteNum(diff) != 0:
		idx = 2
	case secondNum(diff) != 0:
		idx = 1
	default:
		idx = 0
	}
	w.insertSlot(idx, node)
}
func (w *TimerWheel) timerCascade(level int) {
	var (
		guard bool
		clock int64
		diff  int64
		cur   *timerNode
	)
	clock = atomic.LoadInt64(&w.clock)
	var next *list.Element
	for e := w.slot[level].Front(); e != nil; e = next {
		cur = e.Value.(*timerNode)
		diff = cur.trig - clock
		switch {
		case cur.trig <= clock:
			guard = false
		case level == 1:
			guard = secondNum(diff) > 0
		case level == 2:
			guard = minuteNum(diff) > 0
		case level == 3:
			guard = hourNum(diff) > 0
		case level == 4:
			guard = dayNum(diff) > 0
		}
		if guard {
			break
		}
		next = e.Next()
		w.slot[level].Remove(e)
		w.insertTimerNode(cur)
	}
}
func (w *TimerWheel) timerUpdate(curTime time.Time) int {
	var (
		clock  int64
		now    int64
		idx    int32
		diff   int64
		maxIdx int32
		inc    [maxTimerLevel + 1]int64
	)
	now = curTime.UnixNano()
	clock = atomic.LoadInt64(&w.clock)
	diff = now - clock
	diff += w.deltaDiff(clock)
	if diff < minTickerInterval*0.7 {
		return -1
	}
	atomic.StoreInt64(&w.clock, now)
	for idx = maxTimerLevel - 1; 0 <= idx; idx-- {
		inc[idx] = diff / msLimit[idx]
		diff %= msLimit[idx]
	}
	maxIdx = 0
	for idx = 0; idx < maxTimerLevel; idx++ {
		if 0 != inc[idx] {
			w.hand[idx] += inc[idx]
			inc[idx+1] += w.hand[idx] / limit[idx]
			w.hand[idx] %= limit[idx]
			maxIdx = idx + 1
		}
	}
	for idx = 1; idx < maxIdx; idx++ {
		w.timerCascade(int(idx))
	}
	return 0
}