有个疑惑,在goroutine中执行ticker,使用context终止退出,关于执行结果的疑惑

代码如下:

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。
主要是这里有个疑惑,为什么多次执行每次执行结果都不是确定的?

阅读 3.7k
2 个回答

defer执行是要时间的,你cancel后直接就退出了。此时ctx.Done()刚收到信号,可能来不及执行defer。你试一下cancel后再休息一秒,结果应该就一致了

main里面的cancel()执行后,main就退出了,此时整个程序也就退出,所以其他协程可能还没来得及执行相关程序也随着main的退出而退出了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题