- 关键代码片段:
package main
import (
"context"
"fmt"
"time"
)
func main() {
// 创建一个带有取消功能的上下文
ctx, cancel := context.WithCancel(context.Background())
// 启动一个goroutine
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("收到退出通知,退出goroutine")
return
default:
fmt.Println("工作中...")
time.Sleep(1 * time.Second)
}
}
}(ctx)
// 模拟一段时间后取消
time.Sleep(3 * time.Second)
cancel()
time.Sleep(1 * time.Second)
}
- 代码解释:
- 创建上下文和取消函数:
ctx, cancel := context.WithCancel(context.Background())
context.Background()
是Go语言中所有上下文的根上下文。它通常用于程序的顶层。
context.WithCancel(parent)
函数创建了一个新的上下文 ctx
和一个取消函数 cancel
。这个新的上下文可以被取消,当 cancel
函数被调用时,所有基于这个上下文派生的子上下文都会收到取消信号。
- goroutine中的逻辑:
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("收到退出通知,退出goroutine")
return
default:
fmt.Println("工作中...")
time.Sleep(1 * time.Second)
}
}
}(ctx)
- 在这个匿名的goroutine中,使用
select
语句监听 ctx.Done()
通道。当这个通道接收到数据时,意味着上下文被取消,ctx.Done()
通道会被关闭,此时goroutine打印收到退出通知并返回,结束运行。
default
分支在 ctx.Done()
通道没有数据时执行,模拟goroutine的正常工作,这里打印“工作中...”并休眠1秒。
- 主函数中的逻辑:
time.Sleep(3 * time.Second)
cancel()
time.Sleep(1 * time.Second)
time.Sleep(3 * time.Second)
模拟主程序运行一段时间。
cancel()
调用取消函数,向基于 ctx
的所有上下文发送取消信号。
time.Sleep(1 * time.Second)
确保在主程序退出前,有足够的时间让goroutine处理取消信号并退出。