Context
上下文 context.Context  Go 语言中用来设置截止日期,同步信号,传递请求相关的结构体,context 与 gotoutine 有比较密切的关系,是 Go 语言中的独特设计。
Context 作用
- 每个 Context 都会从最顶层 Goroutine 一层一层传递到最下层,context.Context 可以在上层 Goroutine 执行出现错误,会将信号及时同步到下一次层,这样,上层因为某些原因失败时, 下层就可以停掉无用的工作,以减少资源损耗。实际应用:RPC 超时时间设置
- context 中一般意义 context.WithValue 能从父上下文中创建一个子上下文,传值的子上下文使用 context.valueCtx 类型。WithValue 是一对 kv 类型,可用来传值,实际应用:传递全局唯一的调用链
Context 接口
Context 是 Go 语言在 1.7 版本引入的标准库接口,有以下需要实现的方法
- Deadlime 返回 context.Context 被取消的时间,也就是完成工作的截止时间
- Done 返回一个 Channel ,这个 Channel 会在当前工作完成或者被取消后关闭,多次调用 Done 方法会返回同一个Channle
- Err 返回 context.Context 结束的原因,只会在 Done 方法对应的 Channel 关闭时返回非空的值
- Value 从 context.Context 中获取对应的值,对同一个上下文来说,多次调用 Value 并传入相同的 Key 会返回相同的结果。该方法可以用来传递特定的请求。
- 如果 context.Context 被取消,会返回 Canceled 错误;
- 如果 context.Context 超时,会返回 DeadlineExceeded 错误;
type Context interface {
 Deadline() (deadline time.Time, ok bool)
 Done() <-chan struct{}
 Err() error
 Value(key interface{}) interface{}
} 在这里插入图片描述
在这里插入图片描述
使用 context 同步信号
创建一个过期时间为 1s 的上下文, 并向上下文传入 handle 函数,该方法会使用 500ms 的时间处理传入的请求。
package contexttest
import (
 "context"
 "fmt"
 "testing"
 "time"
)
func TestContext(t *testing.T) {
 // 创建一个过期时间为1s的上下文
 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
 defer cancel()
 go handle(ctx, 500*time.Millisecond)
 select {
 case <-ctx.Done():
  fmt.Println("main", ctx.Err())
 }
}
func handle(ctx context.Context, duration time.Duration) {
 select {
 case <-ctx.Done():
  fmt.Println("handle", ctx.Err())
 case <-time.After(duration):
  fmt.Println("process request with",
   duration)
 }
}运行结果:
=== RUN   TestContext
process request with 500ms
main context deadline exceeded
--- PASS: TestContext (1.00s)
PASSContext 创建
- 根 Context: 通过 context.Backgroud() 创建
- 子 Conetxt:context.WithCancel(parentConetxt) 创建
ctx, cancel := context.WithCancel(conetext.Background())- 当前 Context 被取消时,其他的子 context 都会被取消
- 接收取消通知 <- ctx.Done()
测试代码package main
import (
 "context"
 "testing"
 "time"
)
func isCanceled(ctx context.Context) bool {
 select {
 case <-ctx.Done():
  return true
 default:
  return false
 }
}
func TestCanceledByConetxt(t *testing.T) {
 ctx, cancel := context.WithCancel(context.Background())
 for i := 0; i < 5; i++ {
  go func(i int, ctx context.Context) {
   for {
    if isCanceled(ctx) {
     break
    }
   }
   time.Sleep(time.Second * 1)
  }(i, ctx)
 }
 cancel()
}欢迎关注公众号:程序员开发者社区

关注我们,了解更多
参考资料
- https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-context/
- https://zhuanlan.zhihu.com/p/68792989
- https://github.com/golang/go/blob/41d8e61a6b9d8f9db912626eb2bbc535e929fefc/src/context/context.go#L519









