Tuesday, April 30, 2024
HomeGolang5 alternative ways to loop over a time.Ticker in Go (Golang)

5 alternative ways to loop over a time.Ticker in Go (Golang)



The time.Ticker is a very talked-about construction in Go that gives clock ticks at mounted intervals. Internally, it incorporates a channel that delivers subsequent ticks. Utilizing this channel, we are able to create a number of completely different variants of the loop relying on the wants, for instance, whether or not the loop ought to begin instantly, whether or not we’d like a ticker worth, or whether or not we need to cease the ticker correctly whereas this system is working. All these circumstances will likely be described on this article 😊.

If you need to carry out some activity each mounted time frame, use the usual for loop over the C channel of time.Ticker. Such a loop means that you can schedule cron-like duties or employee features, the place some code executes each specified time. Take a look at the instance and the output. We obtain a tick within the loop each second and print its time. After 5 seconds of the primary thread sleeping, the ticker stops, and the app finishes.

Any such time.Ticker loop is appropriate for infinite goroutines. Nevertheless, if in a manufacturing utility you permit a goroutine to terminate earlier than the top of this system, it’s higher to make use of an instance that ensures that the goroutine will terminate accurately.

bundle predominant

import (
    "log"
    "time"
)

func predominant() {
    ticker := time.NewTicker(1 * time.Second)

    go func() {
        for t := vary ticker.C {
            log.Printf("Tick at: %vn", t.UTC())
            // do one thing
        }
    }()

    time.Sleep(5 * time.Second)
    ticker.Cease()
}

Output:

2022/12/06 07:05:49 Tick at: 2022-12-06 06:05:49.450700257 +0000 UTC
2022/12/06 07:05:50 Tick at: 2022-12-06 06:05:50.450801838 +0000 UTC
2022/12/06 07:05:51 Tick at: 2022-12-06 06:05:51.450907566 +0000 UTC
2022/12/06 07:05:52 Tick at: 2022-12-06 06:05:52.451003677 +0000 UTC

A loop with out getting the tick worth

In lots of circumstances, you don’t want to print the tick worth or use it in every other method. So you may ignore it through the use of the clean identifier within the loop: for _ := vary ticker.C or skip the task within the loop altogether: for vary ticker.C. Take a look at the instance:

bundle predominant

import (
    "log"
    "time"
)

func predominant() {
    ticker := time.NewTicker(1 * time.Second)

    go func() {
        for vary ticker.C {
            log.Println("Hey!")
        }
    }()

    time.Sleep(5 * time.Second)
    ticker.Cease()
}

Output:

2022/12/06 19:11:13 Hey!
2022/12/06 19:11:14 Hey!
2022/12/06 19:11:15 Hey!
2022/12/06 19:11:16 Hey!

Generally it’s your decision the time.Ticker loop to return a tick instantly, with out ready for the primary tick from the C channel. It may be helpful in functions that do some work each sure period of time, however the identical work must also be finished proper after startup. For instance, an utility that fills a cache with knowledge ought to do that proper after the beginning after which at equal intervals, reminiscent of each hour. Though the time.Ticker doesn’t assist such an possibility by default, we are able to simulate this utilizing the traditional for loop type:

for <initialization>; <situation>; <submit-situation> {
    <loopBody>
}

Once we go away the <situation> empty, that means that it is going to be true, we guarantee that this loop will execute a minimum of as soon as instantly. Subsequent executions ought to happen in accordance with incoming ticks, so we have to set studying from the Ticker.C channel as <post-condition>. Run the instance and take a look at its output. The primary execution of the loop is fast as a result of there aren’t any extra circumstances within the <initialization> and <situation> sections, and subsequent executions occur each second in accordance with the <post-condition>.

bundle predominant

import (
    "log"
    "time"
)

func predominant() {
    ticker := time.NewTicker(1 * time.Second)

    go func() {
        for ; ; <-ticker.C {
            log.Println("Hey!")
        }
    }()

    time.Sleep(5 * time.Second)
    ticker.Cease()
}

Output:

2022/12/06 19:50:37 Hey!
2022/12/06 19:50:38 Hey!
2022/12/06 19:50:39 Hey!
2022/12/06 19:50:40 Hey!
2022/12/06 19:50:41 Hey!

If you need to create a time.Ticker loop with the fast first tick and use its worth, you should first initialize the variable within the for loop after which assign successive tick values obtained from the time.Ticker to it. Learn the instance to learn the way to do it:

bundle predominant

import (
    "log"
    "time"
)

func predominant() {
    ticker := time.NewTicker(1 * time.Second)

    go func() {
        for t := time.Now(); ; t = <-ticker.C {
            log.Printf("Tick at: %vn", t.UTC())
        }
    }()

    time.Sleep(5 * time.Second)
    ticker.Cease()
}

Output:

2022/12/07 06:08:24 Tick at: 2022-12-07 05:08:24.189026328 +0000 UTC
2022/12/07 06:08:25 Tick at: 2022-12-07 05:08:25.189313138 +0000 UTC
2022/12/07 06:08:26 Tick at: 2022-12-07 05:08:26.189548386 +0000 UTC
2022/12/07 06:08:27 Tick at: 2022-12-07 05:08:27.189798708 +0000 UTC
2022/12/07 06:08:28 Tick at: 2022-12-07 05:08:28.190043492 +0000 UTC

Correctly end the time.Ticker goroutine

If you run the time.Ticker loop in a goroutine, and sooner or later, you need to cease processing, it is advisable to carry out two steps:

  • cease the Ticker
  • be sure that the goroutine wherein the Ticker was working terminated accurately

To cease the Ticker, it is advisable to run the Cease() technique. Nevertheless, the Cease() doesn’t shut the C channel. It solely prevents new ticks from being despatched. Thus, it doesn’t robotically exit the loop and the goroutine. To shut the goroutine, you want an extra sign that, when learn, will trigger it to shut. So to attain all this, we’ll use a for loop with a choose assertion. The choose blocks and waits till considered one of its circumstances can run. In our scenario, it ought to wait both for the worth of the brand new tick from the C channel or for the sign to terminate the goroutine.

Have a look at the predominant() operate within the instance. After 5 seconds of goroutine processing, we cease the Ticker utilizing the Cease() technique and ship a brand new sign to the finished channel. Because of this, the Ticker stops receiving new ticks within the C channel, and the choose assertion reads the worth from the finished, which causes the goroutine to return. Within the first 5 seconds of the app, there are solely messages within the ticker.C channel, so the choose all the time chooses the case with a learn from this channel.

bundle predominant

import (
    "log"
    "time"
)

func predominant() {
    ticker := time.NewTicker(1 * time.Second)
    finished := make(chan struct{})
    go func() {
        for {
            choose {
            case <-finished:
                return
            case <-ticker.C:
                log.Println("Hey!")
            }
        }
    }()

    time.Sleep(5 * time.Second)
    ticker.Cease()
    finished <- struct{}{}
    log.Println("Accomplished")
}

Output:

2022/12/07 06:09:59 Hey!
2022/12/07 06:10:00 Hey!
2022/12/07 06:10:01 Hey!
2022/12/07 06:10:02 Hey!
2022/12/07 06:10:03 Hey!
2022/12/07 06:10:03 Accomplished
RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments