大白话之golang context

背景

学一个东西之前应该先明白他到底是干什么的,如果这个东西没有适用的场景,那你看他的源码就是浪费时间。

四种context

  1. emptyCtx 实现了一个空的context,可以用作根节点
  2. cancelCtx 实现一个带cancel功能的context,可以主动取消
  3. timerCtx实现一个通过定时器timer和截止时间deadline定时取消的context
  4. valueCtx 实现一个可以通过 key、val两个字段来存数据的context

context能干什么?

  1. 传递上下文

比如一个请求过来后,调用了服务A,服务A又调用了服务B,B又调用了C…,那么想在这些服务中间共享一些信息,例如链路追踪的trace_id,可以使用 valueCtx ,这样服务A、B、C都可以通过 ctx.Value(“trace-id”) 获取。

  1. 控制协程关闭

还是一个请求过来,调用了服务A,服务A又调用了服务B,B又调用了C…,如果当请求调用到A、B、C还没有得到结果时就关闭了请求,那么再调用A、B、C就是没有任何意义的,那么就可以利用ctx, cancel := context.WithCancel(context.Background()),让服务A、B、C都
监听ctx.done(), 当在请求调用cancel()时,A、B、C服务看到请求取消了调用,就不在继续执行,省的浪费资源。

  1. 控制超时取消

我们后端的服务一般都会设置一个超时时间,比如A服务调用B服务,如果A调用B 5秒后没有得到响应,就重新发起请求,就可以用到ctx, _ := context.WithTimeout(context.Background(), 5000*time.Millisecond)。当然了你说我自己实现一个定时器不就完了么?但是你要考虑 如果有条件换成了 A调用B,B又调用C这种情况,用上下文的优势就出来了,可以在A调用B超过5秒后也关闭B对C的调用防止资源浪费,当然了这个层级越深优势越大。

原理

当然你可以去看源码,我只是说核心的实现。

type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key interface{}) interface{}
}

关键的还是这个Done()方法
Done():返回一个只读chan,如果可以从该 chan 中读取到数据,则说明 ctx 被取消了

如果我们自己想实现一个取消是这么写。

	done := make(chan struct{})

	go func() {
		for {
			select {
			case <-done:
				fmt.Println("cancel")
				time.Sleep(1000*time.Millisecond)
			default:
				fmt.Println("not cancel")
				time.Sleep(1000*time.Millisecond)
			}
		}

	}()

	fmt.Println("working")
	time.Sleep(1000*time.Millisecond)
	fmt.Println("working")
	time.Sleep(1000*time.Millisecond)
	close(done)

其实context和我们自己写的也差不多,只是他有一个层级的关系,就是前面写到的A调用B、B又调用C,所以层级就是A是B的parent,B是C的parent,当A进行取消的时候也会将B、C取消,说白了就是当A调用close(done)时候,B、C也会调用close(done),只是这个复杂的层级关系context这个包帮你做了,cancelCtx 、timerCtx本质区别就是多了一个定时器,一个是你自己取消,一个是到期了自动帮你取消,valueCtx就是让服务A、B、C(无论多深)都可以获取到某个key=>value对,实现思路也简单,就是一层一层向上的找,比如从服务C执行ctx.Value(“trace-id”) 没有话就去parent B找,B没找到就去A找,A也没找到就是没有了。

总结

知道了应用场景。知道了核心原理,用起来也就没那么难了。

参考

https://zhuanlan.zhihu.com/p/420127690

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值