Golang efficient and low-precision timer implementation

Source: Internet
Author: User
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.




Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.