Golang Timer Traps

Source: Internet
Author: User
Tags set time

The so-called trap is that it is not what you think, and this cognitive error may leave your software with hidden bugs. Just a timer has 3 traps, we'll talk 1) reset traps and 2) channel traps, 3) stop traps are similar to reset traps, explore for yourself.

Where's the Reset trap?

Timer.Reset()The return value of the function is the bool type, and we look at a problem with three even:

    1. What does it mean by its return value?
    2. What is the success we want?
    3. What is failure?
    • Success: The timer expires after a period of time and a timeout event is received.
    • Failure: the opposite of success, we do not receive that event. For failure, we should do something to ensure that our timers play a role.

Does the return value of reset mean this?

By looking at the document and the implementation, Timer.Reset() The return value does not meet our expectations, which is the error . Its return value does not mean that the reset timer succeeds or fails, but instead expresses the state of the timer before resetting:

    • Returns False when the timer has stopped or timed out.
    • Returns True when the timer does not time out.

So, when Reset returns false, we don't think that after a while, the timeout will not come, it may actually come, the timer is already in effect.

Skip the traps and catch the traps

How do I skip the previous traps and let reset match our expected functionality? Directly ignoring reset's return value well, it doesn't help you to achieve the desired effect.

The real trap is the channel of the timer, which is closely related to our expected success and failure. The timer settings we expect to fail are usually only related to the channel: whether the timer has data in the channel before the timer is set Timer.C .

    • If so, we set the timer to fail and we may read an incorrect timeout event.
    • If not, we set the timer to succeed and we get the timeout event at the set time.

Next, explain why the failure is related only to the presence of a timeout event in the channel.

The cache channel size of the timer is only 1, cannot store timeout event more, see source code.

// NewTimer creates a new Timer that will send// the current time on its channel after at least duration d.func NewTimer(d Duration) *Timer {    c := make(chan Time, 1) // 缓存通道大小为1    t := &Timer{        C: c,        r: runtimeTimer{            when: when(d),            f:    sendTime,            arg:  c,        },    }    startTimer(&t.r)    return t}

Once the timer is created, it is run separately, and the data is written to the channel after the timeout, and you read the data out of the channel. the current time-out data is not read, and set a new timer, and then go to the channel to read the data, the results read the last time-out timeout event, seemingly successful, but actually failed, completely fall into the trap.

Cross traps to ensure success

If Timer.Reset() we ensure success, get the results we want? Timer.Reset()before emptying the channel.

    • When the business scenario is simple, there is no need to actively empty the channel. For example, the process is: Set 1 times timer, processing a timer, no interruption in the middle, the next reset before the channel must be empty.
    • When the business scenario is complex, it is not determined if the channel is empty, then it is actively purged.
if len(Timer.C) > 0{    <-Timer.C}Timer.Reset(time.Second)

Test code

Package Mainimport ("FMT" "Time")//in different cases, the return value of Timer.reset () func test1 () {fmt. Println ("1th test: Reset return value and what about?") ") TM: = time. Newtimer (time. Second) Defer TM. Stop () Quit: = Make (chan bool)//Exit Event go func () {time. Sleep (3 * time. Second) Quit <-true} ()//timer does not time out, see Reset's return value if!tm. Reset (time. Second) {fmt. Println ("Not timed out, reset returns false")} else {fmt. PRINTLN ("No timeout, Reset returns True")}//Stop Timer TM. Stop () if!tm. Reset (time. Second) {fmt. Println ("Stop Timer,reset Returns false")} else {fmt.        Println ("Stop Timer,reset Returns True")}//Timer timeout for {select {case <-quit:return Case <-tm. C:if!tm. Reset (time. Second) {fmt. PRINTLN ("Timeout, reset returns false")} else {fmt. PRINTLN ("Timeout, Reset returns True")}}}}func Test2 () {fmt. Println ("\ n the 2nd Test: After timeout, do not read the event in the channel, can reset succeed? ") Sm2start: = time. Now () TM2: = time. Newtimer (Time. Second) time. Sleep (2 * time. Second) fmt. Printf ("Number of events in the pre-reset channel:%d\n", Len (TM2). C)) if!tm2. Reset (time. Second) {fmt. Println ("Do not read the channel data, reset returns false")} else {fmt. Println ("Do not read channel data, RESET returns True")} FMT. Printf ("Number of events in the post Reset channel:%d\n", Len (TM2). C)) Select {Case T: = <-tm2. C:fmt. Printf ("TM2 Start time:%v\n", Sm2start.unix ()) fmt. Printf ("Time of event in channel:%v\n", T.unix ()) if T.sub (Sm2start) <= Time.second+time.millisecond {fmt. Println ("The time in the channel is the time before the SM2 reset, i.e. the first time out, so the second reset failed")}} FMT. Printf ("read the number of events after the channel:%d\n", Len (tm2. C)) tm2. Reset (time. Second) fmt. Printf ("After reset, the number of events in the channel:%d\n", Len (TM2). C) time. Sleep (2 * time. Second) fmt. Printf ("Number of events in the channel after timeout:%d\n", Len (TM2). C))}func test3 () {fmt. Println ("\ n 3rd Test: Empty the channel before reset, as smooth as possible") Smstart: = time. Now () TM: = time. Newtimer (time. Second) time. Sleep (2 * time. Second) If Len (tm. C) > 0 {<-tm. C} TM. Reset (time. Second)//timeout T: = <-tm. C FMT. PRINTF ("TM Start Time:%v\n", Smstart.unix ()) fmt. Printf ("Time of event in channel:%v\n", T.unix ()) if T.sub (Smstart) <= Time.second+time.millisecond {fmt. Println ("The time in the channel is the time before the SM is reset, that is, the first time out, so the second reset failed")} else {fmt. Println ("Time in channel is reset SM time, reset succeeded")}}func main () {test1 () test2 () Test3 ()}
Related Article

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.