使用context在父协程中操作子协程
- context在go中一般在第一个参数传递
- context的底层实现是一个树形结构,基于树形结构context有一个比较好的点:关闭父协程时,底层会自动关闭该父协程下的所有子协程,如下示例:基于ctx1继续创建了ctx2,将ctx2传入子协程中, 6s后关闭ctx1, 但ctx1下的ctx2也被关闭了
var wg sync.WaitGroup
func control(ctx context.Context){
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Println("监控程序退出")
return
default:
fmt.Println("监控信息")
time.Sleep(time.Second)
}
}
}
func main() {
wg.Add(1)
ctx,cancel1 := context.WithCancel(context.Background())
ctx2, _ := context.WithCancel(ctx)
go control(ctx2)
time.Sleep(time.Second*6)
cancel1()
wg.Wait()
fmt.Println("母协程退出")
}
context.WithTimeout 自动退出
var wg sync.WaitGroup
func control(ctx context.Context){
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Println("监控程序退出")
return
default:
fmt.Println("监控信息")
time.Sleep(time.Second)
}
}
}
func main() {
wg.Add(1)
ctx,_ := context.WithTimeout(context.Background(),time.Second * 6)
go control(ctx)
wg.Wait()
fmt.Println("母协程退出")
}
context 存储数据
- context 常用来存储一下与业务无关的数据,如 链路ID
- 原生的context 的数据是存储在树型结构的每个节点,故不适合存储大量数据
var wg sync.WaitGroup
func control(ctx context.Context){
fmt.Printf("traceid : %v \n",ctx.Value("traceid"))
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Println("监控程序退出")
return
default:
fmt.Println("监控信息")
time.Sleep(time.Second)
}
}
}
func main() {
wg.Add(1)
ctx,_ := context.WithTimeout(context.Background(),time.Second * 6)
ctx = context.WithValue(ctx,"traceid","jjjddddfer")
go control(ctx)
wg.Wait()
fmt.Println("母协程退出")
}