In Golang, a ticker channel is commonly used for creating a regularly occurring event. However, it's important to understand how Stop() behaves to ensure proper channel handling.
Consider the following code snippet:
ticker := time.NewTicker(1 * time.Second) go func() { for _ = range ticker.C { log.Println("tick") } log.Println("stopped") }() time.Sleep(3 * time.Second) log.Println("stopping ticker") ticker.Stop() time.Sleep(3 * time.Second)
When ticker.Stop() is called, the ticker is paused, but the channel is not automatically closed. This means that the goroutine will pause but will not terminate. Running the above code produces the following output:
2013/07/22 14:26:53 tick 2013/07/22 14:26:54 tick 2013/07/22 14:26:55 tick 2013/07/22 14:26:55 stopping ticker
Therefore, the goroutine remains blocked waiting for further ticker events.
To resolve this issue, one can use a second channel to communicate the stop request to the ticker goroutine. Here's an example:
package main import ( "log" "sync" "time" ) type Ticker struct { sync.Mutex ticker *time.Ticker stop chan struct{} } func (t *Ticker) Start(d time.Duration) { t.Lock() defer t.Unlock() if t.ticker != nil { t.ticker.Stop() } t.ticker = time.NewTicker(d) t.stop = make(chan struct{}) go func() { for { select { case <-t.ticker.C: log.Println("tick") case <-t.stop: return } } }() } func (t *Ticker) Stop() { t.Lock() defer t.Unlock() if t.stop != nil { close(t.stop) t.ticker.Stop() } } func main() { t := Ticker{} t.Start(1 * time.Second) time.Sleep(3 * time.Second) log.Println("stopping ticker") t.Stop() time.Sleep(3 * time.Second) }
By using a separate stop channel, we can ensure proper termination of the ticker goroutine when the Ticker.Stop() method is called.
The above is the detailed content of How does Ticker.Stop() behave in Golang, and how can we ensure graceful exits for ticker goroutines?. For more information, please follow other related articles on the PHP Chinese website!