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 协议 ,转载请注明出处!