[Golang] - use time.Ticker to do scheduled tasks

Keywords: Go Database SQL

1, Foreword

      golang's time.Ticker is generally used to execute tasks as a time cycle.

2, demo

      This is an example posted on the official website. Its function is to output the current time every 10s.

package main

import (
	"fmt"
	"time"
)

func main() {
	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()
	done := make(chan bool)
	go func() {
		time.Sleep(10 * time.Second)
		done <- true
	}()
	for {
		select {
		case <-done:
			fmt.Println("Done!")
			return
		case t := <-ticker.C:
			fmt.Println("Current time: ", t)
		}
	}
}

3, Analysis

      To understand the code above, study   Go   Timer, then it must start from   time.Ticker   Start with this structure.

//Ticker keeps a channel and passes "tick" to it at regular intervals.
type Ticker struct {
	C <-chan Time // There is a read-only channel of C
	r runtimeTimer
}

type runtimeTimer struct {
	tb uintptr
	i  int

	when   int64
	period int64 // Mark whether it is a period and the corresponding time
	f      func(interface{}, uintptr) // Processing function
	arg    interface{}
	seq    uintptr
}

When using the timing timer, it is obtained through the NewTimer or AfterFunc function.

func NewTimer(d Duration) *Timer {
    c := make(chan Time, 1)
    t := &Timer{
        C: c,
        r: runtimeTimer{
            when: when(d), //Indicates that f is called when the time period d is reached
            f:    sendTime,  // f refers to a function call, where sendTime refers to sending the current time to Timer.C when the d time arrives
            arg:  c,  // Arg means that the parameter arg is passed to f when calling F, and c is used to accept the sending time of sendTime
        },
    }
    startTimer(&t.r)
    return t
}

        The specific implementation logic of the timer is in time.go in runtime, which is implemented through the quadtree heap (the i field in the runtimeTimer structure represents the index in the heap). By constructing a minimum heap, it is ensured that the expired timer can be executed as soon as possible. The timer is executed in a special goroutine: go timerproc()

At this time, let's analyze the above code:

package main

import (
	"fmt"
	"time"
)

func main() {
    //NewTicker () returns a new Ticker that contains a channel field and sends the current time to the channel every time period d.
    //It adjusts the time interval or discards the tick information to accommodate slow recipients.
    //If d < = 0, it will panic. Close the Ticker to release related resources.
	ticker := time.NewTicker(time.Second)

    //Stop() closes a Ticker. After closing, no more tick information will be sent. Stop does not close channel t.C to avoid incorrect read success from that channel
	defer ticker.Stop()
	done := make(chan bool)
	go func() {
		time.Sleep(10 * time.Second)
		done <- true
	}()
	for {
		select {
		case <-done:
			fmt.Println("Done!")
			return
		case t := <-ticker.C:
			fmt.Println("Current time: ", t)
		}
	}
}

NewTicker () returns a new Ticker that contains a channel field and sends the current time to the channel every time period D. It adjusts the time interval or discards the tick information to accommodate slow recipients. If d < = 0, it will panic. Close the Ticker to release related resources.

Stop() closes a Ticker. After closing, no more tick information will be sent. Stop does not close channel t.C to avoid incorrect read success from that channel
 

4, Precautions

  • After the ticker is created, there is not a tick immediately. The first tick is after x seconds (you wrote it yourself).
  • The timer of Go language is essentially a one-way channel. There is a one-way chan of time.Time type in the time.Timer structure type.
  • time.NewTicker regularly triggers the execution of the task. When the next execution comes and the current task has not been completed, it will wait for the current task to execute before executing the next task. Check the go official website documentation and code verification.
  • t.Stop() does not stop the Timer here. This is because stop will stop the Timer. After stopping, the Timer will not be sent again, but stop will not close the channel to prevent errors from reading the channel. If you want to stop the Timer, you can only let the go program end automatically.

5, Reference articles

1. Analyzing the timer of go from time.Ticker

Posted by dminadeo on Sat, 20 Nov 2021 22:28:32 -0800