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