H5W3
当前位置:H5W3 > 其他技术问题 > 正文

Go的context解密

Go中的context包在Go1.7的时候由google贡献引入Go SDK中。在并发的场景下基本都会用到context这个包的功能。 

什么是context?

中文翻译为“上下文”,具体应用在goroutine中。用作goroutine的控制手段。context 主要用来在各个goroutine之间传递上下文。包括:cancel,timeout等。(个人在开发中用作超时控制,类似:前端一个require但是后端比较繁忙。比如5s无法返给前端response。这样就直接返回timeout并且取消这个goroutine。)

随着context 包的引入,标准库的很多接口带上ctx 参数。类似 database/sql 。context基本就是成为控制并发控制&&超时控制的标准用法。可以看某站的源码也是携带大量的context。

为什么会需要context

如果你用过Go写过http。基本上几行代码就可以起来一个server。

在这个server里面,通常一个require就会启动至少一个goroutine来工作;注意是至少一个goroutine。

这些goroutine需要共享这个require的基本数据。例如token,处理require的最大时间(超时才返回数据,请求方超时请求不到)等等。还有就是这么个场景,请求方只是点错了,来了界面,然后立刻关闭了。这样就要快速释放掉创建的goroutine。因为他们已经没用了,他们的结果已经不被需要。当所有的goroutine退出,操作系统就能回收掉这些资源。

还有就是 在Go中server是个“携程模型”,也就是至少一个携程对应处理一个请求。我本人的真实经历(测试环境还好。没造成影响。):再测试的时候,并发访问。某个处理模块慢了,当前系统的请求没有控制,然后超时时间也没有设置。那样等着的goroutine的越来越多。虽然Go官方号称一个goroutine大概是2KB的消耗。但是吧。。看proof的时候 gorouitne达到10W个。内存飙涨。服务不可用。操作系统load飙升。整个服务对外不可用。如果是生产基本就是P0事故。基本就要提桶跑路。

后面我改掉代码。通过设置timeout就避免这个问题。我给请求其他模块的时间设置到Xs.如果超过这个时间没有receive。就直接给请求方一个err或者服务器繁忙。

概括一下:在Go中,我们不能直接killgoroutine,携程的关闭基本就是靠return,Channel。但是在某些情景下面,像我上面说的一个require生成很多子携程,互相之间有关联。需要共享global data。在用channel就挺难操作。

context 用来解决goroutine之间的退出通知元数据传递

context底层实现原理

Go 版本 1.13.1

整体概览:

context包的代码量并不是很多。算上注释也就不到4 500行。真实用的代码估计不到200行。这玩意还是挺有意思的。

网上抄了个context的包的具体内容。

context的接口

在pre_go19.go这个文件中定义的context接口

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

Context时是个interface。定义4个func。都是幂等。也就是说多次调用一个method。得到结果是一样的。

第一方法Done().返回一个channel,可以表示context被去取消的信号:当这个channel被关闭/取消,说明context被取消。注意,这就是个RO的channel。Go基础,读取一个关闭的channel只会读到这个管道对应的类型的0值。也就是可以认为 是个<-channel  类型的channel。因此子携程里读这个channel。除非被close掉。否则没有任何东西能取到。也就是可以利用这个特点:从字携程取到0值。就可以做收尾,快速退出。回收资源。

其他的下次在写吧。挺晚了。20200614 23.40。🙏

本文地址:H5W3 » Go的context解密

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址