相信大家学习go后就或多或少的都看过ctx变量,那么这个ctx到底是干嘛的呢,跟进去发现是Content类型,这里就先浅浅的分析下Content是干嘛的吧
- type Context interface {
- Deadline() (deadline time.Time, ok bool)
- Done() <-chan struct{}
- Err() error
- Value(key interface{}) interface{}
- }
上面就是Context的结构,一共有四个成员变量
Content中文是叫上下文,这个名字有点不是很直观,不知道具体是干嘛的,下面就统计了Content的几个使用场景
1.上下文信息传递,类似中间件(java中的拦截器,过滤器)将处理的信息存起来传给后面的方法
2.精准控制goroutine的运行 (控制孙子类的协程,通知别的协程之类的)
实现上下文传递靠的是Value(key interface{})成员变量
示例
- ctx := context.Background()
- ctx = context.WithValue(ctx, "k1", "1")
- ctx = context.WithValue(ctx, "k2", "2")
注意每次存一个value就会再生成一个子content,所以查找的时候会层层往上查,比如要查k1的值,会先查到k2对应的Content,k2中没有就会往父类k1中去找
除了能将信息传给后面调用的方法,Content还有个更重要的属性就是控制goroutine,我们都知道go的协程很容易开启,所以就要有个精准的关闭来控制它防止因为协程未关闭发生协程泄露
示例
- package main
-
- import (
- "context"
- "fmt"
- "time"
- )
-
- func worker(ctx context.Context) {
- for {
- select {
- case <- ctx.Done():
- fmt.Println("cancel goroutine by context!")
- return
- default:
- fmt.Println("I'm alive")
- time.Sleep(1 * time.Second)
- }
- }
- }
-
- func main() {
- ctx, cancel := context.WithCancel(context.Background())
- go worker(ctx)
- time.Sleep(time.Second * 4)
- cancel() // 通知子goroutine结束
- fmt.Println("over")
- }
上面通过context自带的WithCancel方法将cancel函数传递出来,然后手动调用cancel()函数给goroutine传递了ctx.Done()信号。这样就能精准控制协程的释放了