3
func Tick() {                                                                                                                                         
    fmt.Println("startTime", time.Now().Format("2006-01-02 15:04:05"))                                                                                
    t := time.NewTicker(time.Second * 3)                                                                                                              
    time.Sleep(time.Second * 12)                                                                                                                      
    for {                                                                                                                                             
        stamp := <-t.C                                                                                                                                
        fmt.Println("tickTime", stamp.Format("2006-01-02 15:04:05"))                                                                                  
    }                                                                                                                                                 
}          

Otput from above snippet is:

startTime 2016-06-22 16:22:20

tickTime 2016-06-22 16:22:23

tickTime 2016-06-22 16:22:35

tickTime 2016-06-22 16:22:38

tickTime 2016-06-22 16:22:41

tickTime 2016-06-22 16:22:44


Why has this happend with no timestamp 16:22:26, 16:22:29 when I delay the ticker?

liam_g
  • 314
  • 1
  • 5
  • 15
what is what
  • 1,461
  • 2
  • 12
  • 16
  • Where are you running this? It seems to work fine for me: https://play.golang.org/p/3uVTJq9AfN – Duru Can Celasun Jun 22 '16 at 08:42
  • @DuruCanCelasun You're only waiting for 1 second, which is less than the ticker duration. Wait > tick duration is the problem here. – Linear Jun 22 '16 at 09:20

1 Answers1

10

This is the Ticker source (pardon the line numbers, I copied this off the documentation source page):

    func NewTicker(d Duration) *Ticker {
            if d <= 0 {
                panic(errors.New("non-positive interval for NewTicker"))
            }
            // Give the channel a 1-element time buffer.
            // If the client falls behind while reading, we drop ticks
            // on the floor until the client catches up.
            c := make(chan Time, 1)
            t := &Ticker{
                C: c,
                r: runtimeTimer{
                    when:   when(d),
                    period: int64(d),
                    f:      sendTime,
                    arg:    c,
                },
            }
            startTimer(&t.r)
            return t
        }

Note the comment

// Give the channel a 1-element time buffer.
// If the client falls behind while reading, we drop ticks
// on the floor until the client catches up.

What's happening:

  1. You create the timer
  2. The timer produces its first tick and buffers it.
  3. Now it waits, wakes up, and blocks, waiting for you to consume so it can produce tick 2.
  4. Eventually, your goroutine wakes up and immediately consumes the first two ticks it produced, and it starts producing ticks again.

Edit: In addition, the documention for NewTicker (which Tick is a convenience function for) says:

NewTicker returns a new Ticker containing a channel that will send the time with a period specified by the duration argument. It adjusts the intervals or drops ticks to make up for slow receivers. The duration d must be greater than zero; if not, NewTicker will panic. Stop the ticker to release associated resources.

Though it doesn't explicitly mention it's a channel with a buffer of one.

Jeff P Chacko
  • 4,908
  • 4
  • 24
  • 32
Linear
  • 21,074
  • 4
  • 59
  • 70
  • Where does it actually *adjust* the interval as it claims in the docs? It looks to me like all it does is drop ticks. – Zyl Dec 17 '22 at 15:47