Golang Go语言中一般 context 声明放在哪里合适
有一个函数,要并发访问好几个数据库,返回时间不一样,就叫做 longTimeTask()吧,我想用 context 设置超时,现在试下了,context 声明放在 main 里面,就所有 goroutine 共享了,不符合我要求,如果这样是可以的:
go func() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
longTimeTask(ctx)
}()
后面我发现这样也行:
func longTimeTask(){
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
}
所以想问问哪种最合适
Golang Go语言中一般 context 声明放在哪里合适
更多关于Golang Go语言中一般 context 声明放在哪里合适的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
如果我 CR 的话会觉得第一种好一点,没有那么隐式,因为长任务与超时没有必然联系
更多关于Golang Go语言中一般 context 声明放在哪里合适的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
没有明显区别,要改的话用 IDE 重构功能改也不是特别麻烦。风格这种事,场景多了之后容易分析。
我看其实只有两点区别,传不传入底层 context ,以及谁来控制 3s 的这个 threshold
用入参显示声明就好
从工程化的角度来看,尽量不要引入 implicit variable ,这会增加耦合性和复杂性。如果上下文 context 跟当前函数是高内聚,天然耦合性强的,就直接定义为私有变量,没问题,也就是第二种;但如果 context 会在其他地方被引用,或需要控制,就必须放在外层,作为参数被调用,或者用函数传入,也就是第一种。
总的来看,要视情况而定,单从代码量来看,第二种 4 行代码肯定优于第一种 5 行代码 🐶
一般服务里是一个请求一个 context ,一般框架会直接给你准备好,你一路传下去就行,如果框架没有的话就自己在处理一开始的时候新建一个
这个跟 context 没有关系,还是看业务,如果 longTimeTask 是需要外部来控制 timeout 就是第一种,如果完全不需要外部控制就是第二种
第一种合适,第一种的含义是在主 goroutine 中指定所有派生的 goroutine 都必须在(主 goroutine 视角) 3 秒内做完;第二种意思是主 goroutine 派生一堆 goroutine ,不管多久能做完;但是每个派生 goroutine 单独控制超时 3 秒。
我觉得虽然最终实现出来的效果可能没什么差别,但是从操作语义上觉得还是主 goroutine 统一管控比较好。
最后写出来的效果应该像这样(随手写的,很可能跑不通,但是琢磨应该大致结构大差不差):
- [https://go.dev/play/p/A1ae5LNzsQu]( https://go.dev/play/p/A1ae5LNzsQu)go<br>package main<br><br>import "fmt"<br><br>func main() {<br><br> ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)<br> defer cancel()<br><br> wg := sync.WaitGroup{} <br> for i:= 0; i < 10; i++ {<br> wg.Add(1)<br> go longTimeTask(ctx context.Context) {<br> // some DB query here<br> wg.Done()<br> return<br> }(ctx)<br> }<br> <br> wg.Wait()<br>}}<br><br>
6L 正解.
以上其他 L, 扯淡.
鉴于提问在 go 标签下, go 的 Context, 主要有 2 种用法.
1. 用于替代全局变量, 更安全的透传"偏全局的"参数. 常用于: web 的 http Ctx, 携带 http 请求参数, 并在透传中, 注入新的参数, 向下传.
2. 并发控制. 更优雅的控制 Goroutine 退出. 常用于: db/redis/mq/rpc 等中间件 client 的退出管理.
多看一些 web framework 源码, 在 graceful shutdown 处, 都可看到 context 的典型用法.
其他语言, python 的 django http request 的源码, 也有类似设计.
Context, 是一种设计范式. 至于是要在 main 全局定义, 还是局部定义, 是具体业务场景决定的. 具体问题, 具体分析.
我给出的 2 种用法, 就存在 main 全局定义的 ctx, 也存在定义在局部的 ctx.
PS:
不懂, 就不要强答, 误人子弟.
写代码, 不是八股文. 要搞清楚本质.
错的答案, 比不回答. 更糟糕.