当前位置:网站首页>Go context 基本介绍
Go context 基本介绍
2022-07-04 09:32:00 【动态一时爽,重构火葬场】
在Go1.7中引入了context,包含goroutine运行状态、环境、现场等信息。并逐渐成为并发控制、超时控制的标准做法。
为什么要有context?
在Go的server中通常每个请求都会启动若干个goroutine同时工作(有的去数据库拿数据,有的调用下游接口获取相关数据)。而这些goroutine需要共享该请求的基本数据,例如登录token、处理请求的最大超时时间等。
因此我们可以将Go server看作一个协程模型。但是这个协程模型在没有context可能会出现一些问题。例如在业务高峰期,下游服务的响应变慢,而当前系统请求没有超时控制,那么等待下游服务的协程便会越来越多,最后导致内存占用飙升,甚至导致服务不可用事故。
对于该事故,其实简单设置一下允许下游最长处理时间就可以避免。而context便非常利于这种设置。
context可以在一组goroutine中传递共享值、取消信息、deadline等。
局部的全局变量
在《代码大全》中指出了全局变量的几大弊端
- 无意中修改
- 命名冲突
- 奇异的别名
- 并发问题
- 初始化顺序无法保证
- 阻碍了代码复用
- 干扰了模块化
个人认为全局变量最严重的问题应该是耦合。其他相对好说
但全局变量却也有着提升数据作用域的好处。
于是很多语言便设计出不那么全局的变量。比如Java中的ThreadLocal,在线程内的全局,避免了线程冲突。再比如Go中的context
对于context而言直接体现这一点就是WithValue,而对于WithTimeout、WithCancel实际上也是全局控制变量
基本使用
主要提供了两种方式创建context
- context.Backgroud():上下文默认值,所有其他的上下文都从他衍生。通常用于main函数、初始化、测试或者顶级上下文
- context.TODO():对于不确定应该使用哪种上下文时使用
两种实际都是type emptyCtx int
实际中还是要通过以下四种With方法进行派生
// WithCancel返回父进程的一个副本,并有一个新的Done channel。当返回的cancel函数被调用或父上下文的Done通道被关闭时,返回上下文的Done通道将被关闭,以哪个先发生为准。
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
// WithDeadline返回父上下文的一个副本,其截止日期调整为不迟于d。如果父上下文的截止日期已经早于d, WithDeadline(parent, d)在语义上等价于parent。
// 当截止日期到期、调用返回的cancel函数或父上下文的Done通道被关闭时,返回上下文的Done通道将被关闭,以先发生的情况为准。
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
return WithDeadline(parent, time.Now().Add(timeout))
}
// WithValue返回父元素的副本,其中与键关联的值为val。
//上下文值只用于传递进程和api的请求范围内的数据,而不是传递可选参数给函数。
//提供的键必须是可比较的,不应该是string类型或任何其他内置类型,以避免使用context的包之间的冲突。使用WithValue的用户应该定义自己的键类型。在给接口{}赋值时,为了避免分配,上下文键通常有具体的类型struct{}。另外,导出的上下文关键变量的静态类型应该是指针或接口。
func WithValue(parent Context, key, val interface{
}) Context
传递共享数据
常常用于一些“全局变量”。比如说下面代码中发送请求中的reqID,因为之后代码基本上都要用到,因此可以使用context
个人意见其实没必要用context传递共享数据。如果是功能内聚的代码完全可以抽象为结构,将共享数据作为结构。如果传递环节不多,也可以直接传参。如果是“全局”共享的变量,那也可以通过chan或者其他方法共享,当然context也是其他方法中一种。
func TestContextPassValue(t *testing.T) {
handler := withRequestID(http.HandlerFunc(handle))
http.ListenAndServe("/", handler)
}
const reqKey = 0
func withRequestID(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
// fetch request id from header
rid := req.Header.Get("X-Request-ID")
ctx := context.WithValue(req.Context(), reqKey, rid)
req = req.WithContext(ctx)
next.ServeHTTP(rw, req)
})
}
func handle(rw http.ResponseWriter, req *http.Request) {
reqID := req.Context().Value(reqKey)
...
}
取消goroutine
曾有人说context真正解决的问题就是取消。在本文谈到的三种使用,传递共享数据往往有其他甚至更好的方法能做到;防止goroutine泄露,其实也是一种取消goroutine来达到的目的。但是取消下游服务的功能,却只有context能够以最简单的方式去解决。
防止goroutine泄露
假设我们正在一款聊天软件,它拥有实时扫描用户文件夹来保护“安全”的功能。
func imApp() {
close:=make(chan struct{
})
go scanFiles()
select {
case <-close:
return
}
}
func scanFiles() {
// scan user file
}
这个时候用户通知我们将app关闭,那么就可能app其他功能关闭了,可是扫描文件的goroutine一直在运行。
此时为了防止这种情况的出现,可以使用context去防止这种无限运转的goroutine泄露。
func imApp() {
close := make(chan struct{
})
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go scanFiles(ctx)
select {
case <-close:
return
}
}
func scanFiles(ctx context.Context) {
select {
case <-ctx.Done():
return
default:
// scan user file partly
}
}
这样最多在取消的时候,扫描了一遍。
慎用context
context虽然非常棒,非常适合写server,尤其对于取消操作。但是如果到处滥用,可能就像病毒一样扩散。并且context实际是链表实现,效率相对来说比较低。
Ref
- https://zhuanlan.zhihu.com/p/68792989
- https://www.cnblogs.com/qcrao-2018/p/11007503.html
- https://www.zhihu.com/question/269905592/answer/364438511
- https://faiface.github.io/post/context-should-go-away-go2/
边栏推荐
- Report on investment analysis and prospect trend prediction of China's MOCVD industry Ⓤ 2022 ~ 2028
- 2022-2028 global gasket plate heat exchanger industry research and trend analysis report
- pcl::fromROSMsg报警告Failed to find match for field ‘intensity‘.
- HMS core helps baby bus show high-quality children's digital content to global developers
- ArrayBuffer
- Write a jison parser from scratch (6/10): parse, not define syntax
- 2022-2028 global visual quality analyzer industry research and trend analysis report
- Write a jison parser (7/10) from scratch: the iterative development process of the parser generator 'parser generator'
- Global and Chinese market of planar waveguide optical splitter 2022-2028: Research Report on technology, participants, trends, market size and share
- Global and Chinese markets for laser assisted liposuction (LAL) devices 2022-2028: Research Report on technology, participants, trends, market size and share
猜你喜欢
Clion console output Chinese garbled code
LeetCode 74. Search 2D matrix
After unplugging the network cable, does the original TCP connection still exist?
Solve the problem of "Chinese garbled MySQL fields"
C language - Introduction - Foundation - syntax - [main function, header file] (II)
Reload CUDA and cudnn (for tensorflow and pytorch) [personal sorting summary]
HMS core helps baby bus show high-quality children's digital content to global developers
Latex download installation record
How do microservices aggregate API documents? This wave of show~
Daughter love: frequency spectrum analysis of a piece of music
随机推荐
Svg image quoted from CodeChina
Write a jison parser (7/10) from scratch: the iterative development process of the parser generator 'parser generator'
Mac platform forgets the root password of MySQL
Les différents modèles imbriqués de listview et Pageview avec les conseils de flutter
Function comparison between cs5261 and ag9310 demoboard test board | cost advantage of cs5261 replacing ange ag9310
Global and Chinese market of wheel hubs 2022-2028: Research Report on technology, participants, trends, market size and share
Global and Chinese market of planar waveguide optical splitter 2022-2028: Research Report on technology, participants, trends, market size and share
A subclass must use the super keyword to call the methods of its parent class
Leetcode (Sword finger offer) - 35 Replication of complex linked list
[C Advanced] file operation (2)
Launpad | basic knowledge
2022-2028 global small batch batch batch furnace industry research and trend analysis report
Flutter 小技巧之 ListView 和 PageView 的各种花式嵌套
Investment analysis and future production and marketing demand forecast report of China's paper industry Ⓥ 2022 ~ 2028
How to display √ 2 on the command line terminal ̅? This is actually a blog's Unicode test article
Fatal error in golang: concurrent map writes
Report on research and investment prospect prediction of China's electronic grade sulfuric acid industry (2022 Edition)
About the for range traversal operation in channel in golang
C language - Introduction - Foundation - syntax - [identifier, keyword, semicolon, space, comment, input and output] (III)
保姆级JDEC增删改查练习