This is the fifth day of my participation in the November Gwen Challenge. Check out the details: The last Gwen Challenge 2021

Timer

A Timer is a single event Timer, which means that the Timer is executed only once and then ends.

Create:

Time. NewTimer(d Duration) : Creates a timer

  • Parameter is waiting event
  • Triggers an event immediately after the time arrives

SRC /time/sleep.go:Timer defines the Timer data structure:

type Timer struct {
	C <-chan Time
	r runtimeTimer
}
Copy the code

The Timer exposes only one channel to the outside world. When the specified time comes, the system time, namely an event, will be written to the channel.

Use the timer

Set timeout

For example, when waiting for data in a connection, set a timeout period. When the time arrives and still no data is obtained, it will be timeout.

func WaitChannel(conn <-chan string) bool {
	timer := time.NewTimer(3 * time.Second)

	select {
	case <- conn:
		timer.Stop()
		return true
	case <- timer.C: / / timeout
		fmt.Println("WaitChannel timeout")
		return false}}Copy the code

In the previous example, the SELECT statement polls conn and timer.c. The timer will write data to timer.c after 3s. If conn has no data within 3s, it will judge that it has timed out.

Delayed execution method

Sometimes we want a method to execute at some point in the future:

func DelayFunction(a) {
  timer := time.NewTimer(5 * time.Second)
  
  select {
  case <- time.C
    fmt.Println("Of 5 s,...")}}Copy the code

DelayFunction() will wait for the timer event to arrive before executing the subsequent method (printing).

Timer External interface

Creating a Timer

func NewTimer(d Duration) *Timer :

  • Specify a time to create a Timer. Once the Timer is created, it starts. No additional startup is required.
  • Creating a Timer means giving a timing task to the system daemon coroutine, which manages all timers and sends the current time as an event into the Timer’s pipe when the Timer’s time is up.

Stop timer

Func (t *Timer) Stop() bool:

  • The Timer can be stopped at any time after it is created
  • The return value indicates whether timeout occurs:
    • True: No event will be sent if the timer does not time out
    • False: Stops after the timer times out

Reset timer

func (t *Timer) Reset(d Duration) bool:

  • A timer that has expired or stopped can be reactivated by resetting it
  • The action of resetting is essentially stopping the timer and then starting it. The return value is the return value of stopping the timer.

Simple interface

After()

Sometimes we just want to wait for the specified time, there is no need to stop the timer in advance, and there is no need to reuse the timer, then we can use anonymous timer:

func AfterDemo(a){
  log.Println(time.Now)
  <- time.After(1 * time.Second)
  log.Println(time.Now())
}
Copy the code

The printing interval is 1s, which is actually still a timer, but the code is more concise.

AfterFunc()

AfterFunc can be used to defer a method call with a more concise implementation:

func AfterFunc(d Duration, f func()) *Timer

Example:

func AfterFuncDemo(a) {
  log.Println("AfterFuncDemo start", time.Now())
  time.AfterFunc(1 * time.Second, func(a){
    log.Println("AfterFuncDemo end", time.Now())
  })
  
  time.Sleep(2 * time.Second) // Wait for the coroutine to exit
}
Copy the code
  • AfterFuncDemo() prints a time, then uses AfterFunc to start a timer and specifies that when the timer ends, a method is executed to print the end time.
  • Time.afterfunc () is executed asynchronously, so you need to sleep for the specified coroutine to exit at the end of the function, otherwise the function may end without executing the coroutine.

Ticker

A Ticker is a periodic timer that periodically triggers an event. Its data structure is exactly the same as the Timer:

type Timer struct {
	C <-chan Time
	r runtimeTimer
}
Copy the code

A time is specified when the Ticker is created as the cycle for event firing. This is the main difference between Ticker and Timer.

Ticker use

Timing task

For example, log every 1s:

func TickerDemo(a) {
  ticker := time.NewTicker(1 * time.Second)
  defer ticker.Stop()
  
  for range ticker.C {
    log.Println("ticker...")}}Copy the code

For range Ticker.C will continuously fetch events from the pipe and print a log line after receiving the event. If there is no data in the pipe, the ticker will periodically write events to the pipe, so the above program will periodically print the log.

Ticker external interface

Creating a Timer

func NewTicker(d Durtion) * Ticker :

  • parameterdIs the period during which timer events are triggered.

Stop timer

func (t * Ticker) Stop() :

  • This method stops the timer, meaning no events are written to the timer pipe, but the pipe is not closed. The pipe will be released automatically at the end of its life cycle after completion of use.
  • The Ticker must be released after it is used up. Otherwise, resource leaks will occur and CPU resources will be continuously consumed.

Simple interface

If we need a timed polling task, we can use a simple Tick function to get the pipe of the timer. The function prototype is as follows:

func TIck(d Durtion) <-chan Time :

  • This function actually creates a Ticker inside, but does not return it, so there is no way to stop the Ticker. So, be sure to consider specific usage scenarios.

The wrong sample

func WorngTicker(a) {
  for {
    select {
    case <- time.Tick(1 * time.Second)
      log.Println("Resource leak")}}}Copy the code

In the example above, select creates a timer every time it checks a case statement, and the for loop continuously executes the SELECT statement. As a result, more and more timers in the system consume CPU resources and eventually the CPU runs out.

Correct usage:

func demo(t interface{}) {
    for {
        select {
        case <-t.(*time.Ticker).C:
            println("1s timer")}}}func main(a) {
    t := time.NewTicker(time.Second * 1)
    go demo(t)
    select{}}Copy the code