代码如下:
package main
import (
"context"
"fmt"
"time"
)
func main() {
ticker := time.NewTicker(time.Second)
ctx, cancel := context.WithCancel(context.Background())
TickerHandle(ticker, ctx)
time.Sleep(3 * time.Second)
cancel()
}
func TickerHandle(ticker *time.Ticker, ctx context.Context) {
go func() {
defer func() {
ticker.Stop()
fmt.Println("Defer Ticker Stop!")
}()
for {
select {
case <-ctx.Done():
fmt.Println("Ticker Stop1")
return
case <-ticker.C:
fmt.Println("Ticker...")
}
}
fmt.Println("Ticker Stop2")
}()
}
执行结果1:
Ticker...
Ticker...
执行结果2:
Ticker...
Ticker...
Ticker...
Ticker Stop1
Defer Ticker Stop!
执行结果3:
Ticker....
Ticker....
Ticker....
Ticker Stop1
执行结果4:
Ticker...
Ticker...
Ticker...
尝试在go1.12~1.16中执行,每次执行结果是不确定的,所以使用context.WithCancel()这种方式是没有办法真正使执行ticker的goroutine停止退出,需要使用channel。
主要是这里有个疑惑,为什么多次执行每次执行结果都不是确定的?
defer执行是要时间的,你cancel后直接就退出了。此时ctx.Done()刚收到信号,可能来不及执行defer。你试一下cancel后再休息一秒,结果应该就一致了