前言
这是Go十大常见谬误系列的第8篇:并发编程中Context应用常见谬误。素材来源于Go布道者,现Docker公司资深工程师Teiva Harsanyi。
本文波及的源代码全副开源在:Go十大常见谬误源代码,欢送大家关注公众号,及时获取本系列最新更新。
Context是什么
Go语言规范库里有一个package叫context
,该package里定义了context.Context类型,在并发编程里十分有用,然而也常常被开发者误会。
官网对Context的表述是:
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
光看这段形容,还是很容易让人迷糊的,咱们接下来具体看看Context到底是什么以及能够帮忙咱们做什么事件。
Context顾名思义,示意的是goroutine的上下文,Context定义如下所示:
// A Context carries a deadline, cancellation signal, and request-scoped values// across API boundaries. Its methods are safe for simultaneous use by multiple// goroutines.type Context interface { // Done returns a channel that is closed when this Context is canceled // or times out. Done() <-chan struct{} // Err indicates why this context was canceled, after the Done channel // is closed. Err() error // Deadline returns the time when this Context will be canceled, if any. Deadline() (deadline time.Time, ok bool) // Value returns the value associated with key or nil if none. Value(key interface{}) interface{}}
Context能够通过超时设置、携带勾销信号、附加参数信息来不便goroutine里做相应的逻辑管制。
超时管制。 通过
context.WithTimeout
函数和context.WithDeadline
函数能够创立一个有超时工夫的Context。通过Context的Done
函数能够判断是否超时了。func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
勾销信号。通过
context.WithCancel
函数能够创立一个接管cancel信号的Context。通过Context的Done
函数能够判断是否收回了cancel信号。父Context收回的cancel信号,子Context也能够接管到。func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
附加参数信息。通过
context.WithValue
函数能够给Context增加参数。其中key和value都是空接口类型(interface{}
)。通过Context的Value
函数能够获取附加参数信息。func WithValue(parent Context, key, val any) Context
在理论开发过程中,Context的应用流程个别是:
- Step 1: 创立Context,给Context指定超时工夫,设置勾销信号,或者附加参数(链路跟踪里常常应用Context里的附加参数,传递IP等链路跟踪信息)。
Step 2: goroutine应用Step 1里的Context作为第一个参数,在该goroutine里就能够做如下事件:
- 应用Context里的
Done
函数判断是否达到了Context设置的超时工夫或者Context是否被被动勾销了。 - 应用Context里的
Value
函数获取该Context里的附加参数信息。 - 应用Context里的
Err
函数获取谬误起因,目前起因就2个,要么是超时,要么是被动勾销。
- 应用Context里的
有2点要补充:
- 第一,Context是能够组合的。比方,咱们能够通过
context.WithTimeout
创立一个有超时工夫的Context,再调用context.WithValue
增加一些附加参数信息。 - 第二,多个goroutine能够共享同一个Context,能够通过该Context的超时设置、携带勾销信号以及附加参数来管制多个goroutine的行为。
常见谬误
在Context应用过程中有以下几个常见谬误:
第一,不执行
cancel
函数去开释Context资源。对于
context.WithTimeout
、context.WithDeadline
、context.WithCancel
函数返回的cancel函数,须要做执行。官网阐明如下:Canceling this context releases resources associated with it, so code should call cancel as soon as the operations running in this Context complete:
参考代码示例:
func slowOperationWithTimeout(ctx context.Context) (Result, error) { ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) defer cancel() // releases resources if slowOperation completes before timeout elapses return slowOperation(ctx)}
第二,不加超时管制,如果执行了十分耗时的rpc操作或者数据库操作,就会阻塞程序。如果rpc调用接口或者数据库操作接口反对传递Context参数,倡议加上超时设置。代码示例参考如下:
ctx, cancel := context.WithTimeout(parent, 100 * time.Millisecond)response, err := grpcClient.Send(ctx, request)
举荐浏览
- Go十大常见谬误第1篇:未知枚举值
- Go十大常见谬误第2篇:benchmark性能测试的坑
- Go十大常见谬误第3篇:go指针的性能问题和内存逃逸
- Go十大常见谬误第4篇:break操作的注意事项
- Go十大常见谬误第5篇:Go语言Error治理
- Go十大常见谬误第6篇:slice初始化常犯的谬误
- Go十大常见谬误第7篇:不应用-race选项做并发竞争检测
- Go面试题系列,看看你会几题?
开源地址
文章和示例代码开源在GitHub: Go语言高级、中级和高级教程。
公众号:coding进阶。关注公众号能够获取最新Go面试题和技术栈。
集体网站:Jincheng's Blog。
知乎:无忌。
福利
我为大家整顿了一份后端开发学习材料礼包,蕴含编程语言入门到进阶常识(Go、C++、Python)、后端开发技术栈、面试题等。
关注公众号「coding进阶」,发送音讯 backend 支付材料礼包,这份材料会不定期更新,退出我感觉有价值的材料。还能够发送音讯「进群」,和同行一起交流学习,答疑解惑。
References
- 参考文章:https://itnext.io/the-top-10-...
- 官网文档:https://pkg.go.dev/context
- 官网Context入门介绍:https://go.dev/blog/context
- Context应用介绍:https://mp.weixin.qq.com/s/Po...
- https://www.digitalocean.com/...