go并发控制
go实现对并发控制的几种方式
- WaitGroup
- Channel + Select
- Context
WaitGroup
1 | |
输出
1 | |
Channel + Select
1 | |
Context
概述
Go 语言中的每一个请求的都是通过一个单独的 Goroutine 进行处理的,HTTP/RPC 请求的处理器往往都会启动新的 Goroutine 访问数据库和 RPC 服务,我们可能会创建多个 Goroutine 来处理一次请求,而 Context 的主要作用就是在不同的 Goroutine 之间同步请求特定的数据、取消信号以及处理请求的截止日期
Context的调用是链式的,通过WithCancel,WithDeadline,WithTimeout或WithValue派生出新的 Context。当父Context被取消时,其派生的所有Context都将取消
使用
启动了3个goroutine进行不断的循环等待,每一个都使用了Context进行跟踪,当使用cancel函数通知取消时,所有基于这个Context或者衍生的子Context都会收到通知,当Context取消时,得到一个关闭channel(ctx.Done),从关闭的ctx.Done可以读取值,退出select,最终释放goroutine。
1 | |
输出
1 | |
实现
核心Context接口
1 | |
- Deadline:返回当前
Context被取消的时间,也就是完成工作的截止日期 - Done:返回一个 Channel,这个 Channel 会在当前工作完成或者上下文被取消之后关闭,多次调用
Done方法会返回同一个 Channel - Err:返回当前
Context结束的原因,它只会在Done返回的 Channel 被关闭时才会返回非空的值- 如果当前
Context被取消就会返回Canceled错误; - 如果当前
Context超时就会返回DeadlineExceeded错误
- 如果当前
- Value:从
Context中返回键对应的值,对于同一个上下文来说,多次调用Value并传入相同的Key会返回相同的结果,这个功能可以用来传递请求特定的数据
根Context
golang默认的context包已经有emptyCtx实现了Contex接口,具体为Background 和 TODO两个context。其中,context.Background() 是context上下文中最顶层的默认值,所有其他的上下文都应该从 context.Background() 演化出来。(TODO实际基本很少用,只有当不知道该使用什么Context的时候,可以使用这个)
1 | |
1 | |
Context的继承衍生
通过以下With函数,可创建一颗Context树,树的每个节点都可以有任意多个子节点,节点层级可以有任意多个。
1 | |
WithCancel:传递一个父Context作为参数,返回子Context,以及一个取消函数用来取消Context。
WithDeadline:和WithCancel差不多,它会多传递一个截止时间参数,意味着到了这个时间点,会自动取消Context,当然我们也可以不等到这个时候,可以提前通过取消函数进行取消。
WithTimeout:和WithDeadline基本上一样,这个表示是超时自动取消,是多少时间后自动取消Context的意思。
WithValue:此函数和取消Context无关,它是为了生成一个绑定了一个键值对数据的Context,这个绑定的数据可以通过Context.Value方法访问到,这是我们实际用经常要用到的技巧,一般我们想要通过上下文来传递数据时,可以通过这个方法,如我们需要tarce追踪系统调用栈的时候
Reference
- https://golang.org/pkg/context/
- https://blog.golang.org/context
- https://www.sohamkamani.com/blog/golang/2018-06-17-golang-using-context-cancellation/
- https://www.flysnow.org/2017/05/12/go-in-action-go-context.html
- https://draveness.me/golang/concurrency/golang-context.html
- https://juejin.im/post/5a6873fef265da3e317e55b6
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!