Home  >  Article  >  Backend Development  >  How does Ticker.Stop() behave in Golang, and how can we ensure graceful exits for ticker goroutines?

How does Ticker.Stop() behave in Golang, and how can we ensure graceful exits for ticker goroutines?

Linda Hamilton
Linda HamiltonOriginal
2024-11-09 04:38:02551browse

How does Ticker.Stop() behave in Golang, and how can we ensure graceful exits for ticker goroutines?

Ticker Stop behavior in Golang: Handling Graceful Exits

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!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn