This is a creation in Article, where the information may have evolved or changed.
Golang default timers are provided through the time module, whether golang,libev,libevent or not, timers are implemented through the smallest heap, causing Adding a timer time complexity of O (LGN) is inefficient when a large number of timers are required, so Linux provides a time-wheel-based implementation that we provide this time
The timer implementation is the standard Linux time wheel implementation method. Of course, I was the Skynet (HTTPS://GITHUB.COM/CLOUDWU/SKYNET/BLOB/MASTER/SKYNET-SRC/SKYNET_TIMER.C) of the timer transplanted over, stealing innocence ...
Paste a Linux time wheel data structure, if you are unfamiliar with the words can refer to two articles:
1.http://www.ibm.com/developerworks/cn/linux/l-cn-timers/
2.http://blog.csdn.net/lonewolfxw/article/details/8034395
Let's take a look at how to use
Package Timerimport ("FMT", "sync/atomic" "Testing" "Time") var sum int32 = 0var N int32 = 300var tt *timerfunc now () {FMT. Println (time. Now (). Format ("2006-01-02 15:04:05")) atomic. AddInt32 (&sum, 1) V: = Atomic. LoadInt32 (&sum) If v = = 2*n {tt. Stop ()}}func Testtimer (t *testing. T) {timer: = New (Time.millisecond *) TT = TIMERFMT. PRINTLN (timer) var i int32for i = 0; i < N; i++ {timer. Newtimer (Time.millisecond*time. Duration (10*i), now) timer. Newtimer (Time.millisecond*time. Duration (10*i), now)}timer. Start () if sum! = 2*n {t.error ("Failed")}}
Timer: = New (Time.millisecond * 10) We define a timer with a tick of 0.01s, cycle 300 times each time 2 timeout is started, the callback will be sum+1, so the last sum should be equal to 600.
This is my Golang debut, perhaps the code is not very normative, have the time to please more review review
GitHub Address: Https://github.com/Skycrab/code/blob/master/Go/timer/timer.go
Package Timerimport ("Container/list" "FMT" "Sync" "Time")//referer https://github.com/cloudwu/skynet/blob/master/ Skynet-src/skynet_timer.cconst (time_near_shift = 8time_near = 1 << time_near_shifttime_level_shift = 6TIME_ Level = 1 << time_level_shifttime_near_mask = Time_near-1time_level_mask = time_level-1) type Timer Stru CT {near [time_near]*list. LISTT [4][time_level]*list. Listsync.mutextime Uint32tick time. Durationquit Chan struct{}}type Node struct {expire uint32f func ()}func (n *node) string () string {return FMT. Sprintf ("node:expire,%d", N.expire)}func New (d time. Duration) *timer {t: = new (Timer) t.time = 0t.tick = Dt.quit = Make (chan struct{}) var i, j intfor i = 0; i < time_near; i++ {T.near[i] = list. New ()}for i = 0; I < 4; i++ {for j = 0; J < Time_level; J + + {T.t[i][j] = list. New ()}}return t}func (t *timer) AddNode (n *node) {expire: = n.expirecurrent: = T.timeif (Expire | Time_near_mask) = = (Current | Time_near_mask) {t.near[expire&Amp Time_near_mask]. Pushback (N)} else {var i uint32var mask uint32 = time_near << Time_level_shiftfor i = 0; i < 3; i++ {if (expire | (mask-1)) = = (Current | (mask-1)) {break}mask <<= time_level_shift}t.t[i][(expire>> (time_near_shift+i*time_level_shift)) &TIME_ Level_mask]. Pushback (n)}}func (t *timer) Newtimer (d time. Duration, F func ()) *node {n: = new (Node) n.f = ft. Lock () N.expire = UInt32 (D/t.tick) + t.timet.addnode (n) t.unlock () return N}func (t *timer) string () string {return FMT. Sprintf ("timer:time:%d, tick:%s", T.time, T.tick)}func dispatchlist (front *list. Element) {for e: = Front; E! = nil; e = E.next () {node: = E.value. ( *node) Go node.f ()}}func (t *timer) movelist (level, idx int) {VEC: = T.t[level][idx]front: = Vec. Front () Vec. Init () for e: = front; E! = nil; E = E.next () {node: = E.value. ( *node) T.addnode (Node)}}func (t *timer) shift () {T.lock () var mask uint32 = time_neart.time++ct: = T.timeif ct = = 0 {t.movel IST (3, 0)} else {time: = ct >> time_near_sHiftvar I int = 0for (CT & (mask-1)) = = 0 {idx: = Int (time & time_level_mask) if idx! = 0 {t.movelist (i, IDX) Brea K}mask <<= time_level_shifttime >>= time_level_shifti++}}t.unlock ()}func (t *Timer) execute () {t.Lock () idx : = T.time & Time_near_maskvec: = T.near[idx]if VEC. Len () > 0 {front: = Vec. Front () Vec. Init () T.unlock ()//dispatch_list don ' t need lockdispatchlist (front) Return}t.unlock ()}func (t *timer) update () {//try to Dispatch Timeout 0 (rare condition) t.execute ()//Shift time first, and then dispatch timer Messaget.shift () T.execute ()}fun C (t *timer) Start () {tick: = time. Newticker (T.tick) defer tick. Stop () for {select {case <-tick. C:t.update () Case <-t.quit:return}}}func (t *timer) Stop () {Close (t.quit)}
familiar with Skynet's children's shoes look at this code should be very familiar with, look forward to the emergence of Golang Daniel also wrote a game server framework, this should be the voice of many people.