context

微信扫一扫,分享到朋友圈

context

context:

主要的用处如果用一句话来说,是在于简化在多个go routine传递上下文数据,控制goroutine的生命周期。

应用场景:

1.官方http包使用context传递请求的上下文数据

2.gRpc使用context来终止某个请求产生的routine树

3.关联任务的取消

…….

A Context carries a deadline, a cancellation signal, and other values across

基本操作:

import (
"context"
)
根Context:通过context.Background() 创建
子Context:context.WithCancel(parentContext) 创建
ctx,cancel := context.WithCancel(context.Backgroup())
ctx可以传入到接下来的子任务,cancel可以取消当前Context,
当前Context被取消,基于他的子context都会被取消
接受取消通知  <- ctx.Done()

context.Background(),创建一个 根Context实例 =》 emptyCtx

func Background() Context {
return background
}
background = new(emptyCtx)
type Context interface {
//返回一个time.Time,表示当前Context应该结束的时间,ok则表示有结束时间
Deadline() (deadline time.Time, ok bool)
//返回一个关闭的channel (Done returns a channel that's closed )当timeout或者调用cancel方法时,将会触发Done
Done() <-chan struct{}
//context被取消的原因
Err() error
//context实现共享数据存储的地方,是协程安全的
Value(key interface{}) interface{}
}

context库中,有4个关键方法:

  • WithCancel 返回一个cancel函数,调用这个函数则可以主动停止goroutine。
func main() {
root := context.Background()
//ctx1, cancel := context.WithDeadline(root, time.Now().Add(6 * time.Second))
ctx1, cancel := context.WithCancel(root)
ctx2 := context.WithValue(ctx1, "key2", "value2")
go watch(ctx2)
time.Sleep(10 * time.Second)
fmt.Println("通知监控停止")
cancel()
time.Sleep(5 * time.Second)
}
func watch(ctx context.Context) {
for {
select {
case <- ctx.Done():
fmt.Println(ctx.Value("key2"), "监控退出了。")
return
default:
fmt.Println(ctx.Value("key2"), "go rountine 监控中。。。")
time.Sleep(2 * time.Second)
}
}
}
输出:
value2 go rountine 监控中。。。
value2 go rountine 监控中。。。
value2 go rountine 监控中。。。
value2 go rountine 监控中。。。
value2 go rountine 监控中。。。
通知监控停止
value2 监控退出了。
  • WithValue WithValue可以设置一个key/value的键值对,可以在下游任何一个嵌套的context中通过key获取value。
func main() {
root := context.Background()
ctx1 := context.WithValue(root, "key1", "value1")
ctx2 := context.WithValue(ctx1, "key2", "value2")
fmt.Println(ctx1.Value("key1"))
fmt.Println(ctx1.Value("key11"))
fmt.Println(ctx2.Value("key2"))
}
输出:
value1
<nil>
value2
  • WithTimeout 函数可以设置一个time.Duration,到了这个时间则会cancel这个context。
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
return WithDeadline(parent, time.Now().Add(timeout))
}
shutDown := func(interface{}) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if e := httpSrv.Shutdown(ctx); e != nil {
log.Errorf("cronsun node pprof, metrics http server shutdown failed, error: %s", e.Error())
} else {
log.Errorf("cronsun node pprof, metrics http server shutdown success~~")
}
}
  • WithDeadline WithDeadline函数跟WithTimeout很相近,只是WithDeadline设置的是一个时间点。
func main() {
d := time.Now().Add(500 * time.Millisecond) //500 ms
ctx, cancel := context.WithDeadline(context.Background(), d)
defer cancel()
c := make(chan bool)
//模拟耗时代码
go func() {
time.Sleep(400 * time.Millisecond) //修改数值大于 500
c <- true                          //返回
}()
select {
case flag := <-c: //从chan 获取值
if flag {
fmt.Println("执行任务成功")
} else {
fmt.Println("执行任务失败")
}
case <-ctx.Done(): //是ctx的通道先返回的数据
fmt.Println("执行任务超时~")
}
}

欢迎关注我们的微信公众号,每天学习Go知识

西安奔驰女车主:公司已破产 只想做一个普通人

上一篇

BCG报告全面揭秘美国贸易限制带来的影响

下一篇

你也可能喜欢

context

长按储存图像,分享给朋友