有一个函数,要并发访问好几个数据库,返回时间不一样,就叫做 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()
}
所以想问问哪种最合适
1
pennai 2022-11-14 00:22:22 +08:00 2
如果我 CR 的话会觉得第一种好一点,没有那么隐式,因为长任务与超时没有必然联系
|
2
CEBBCAT 2022-11-14 02:00:31 +08:00
没有明显区别,要改的话用 IDE 重构功能改也不是特别麻烦。风格这种事,场景多了之后容易分析。
我看其实只有两点区别,传不传入底层 context ,以及谁来控制 3s 的这个 threshold |
3
securityCoding 2022-11-14 03:11:29 +08:00 via Android
用入参显示声明就好
|
4
tikazyq 2022-11-14 09:39:35 +08:00
从工程化的角度来看,尽量不要引入 implicit variable ,这会增加耦合性和复杂性。如果上下文 context 跟当前函数是高内聚,天然耦合性强的,就直接定义为私有变量,没问题,也就是第二种;但如果 context 会在其他地方被引用,或需要控制,就必须放在外层,作为参数被调用,或者用函数传入,也就是第一种。
总的来看,要视情况而定,单从代码量来看,第二种 4 行代码肯定优于第一种 5 行代码 🐶 |
5
ScepterZ 2022-11-14 09:46:54 +08:00
一般服务里是一个请求一个 context ,一般框架会直接给你准备好,你一路传下去就行,如果框架没有的话就自己在处理一开始的时候新建一个
|
6
Akiya 2022-11-14 10:59:44 +08:00
这个跟 context 没有关系,还是看业务,如果 longTimeTask 是需要外部来控制 timeout 就是第一种,如果完全不需要外部控制就是第二种
|
7
RedisMasterNode 2022-11-14 11:28:32 +08:00
第一种合适,第一种的含义是在主 goroutine 中指定所有派生的 goroutine 都必须在(主 goroutine 视角) 3 秒内做完;第二种意思是主 goroutine 派生一堆 goroutine ,不管多久能做完;但是每个派生 goroutine 单独控制超时 3 秒。
我觉得虽然最终实现出来的效果可能没什么差别,但是从操作语义上觉得还是主 goroutine 统一管控比较好。 最后写出来的效果应该像这样(随手写的,很可能跑不通,但是琢磨应该大致结构大差不差): - [https://go.dev/play/p/A1ae5LNzsQu]( https://go.dev/play/p/A1ae5LNzsQu) ```go package main import "fmt" func main() { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() wg := sync.WaitGroup{} for i:= 0; i < 10; i++ { wg.Add(1) go longTimeTask(ctx context.Context) { // some DB query here wg.Done() return }(ctx) } wg.Wait() }} ``` |
8
akaHenry 2022-11-15 10:08:56 +08:00 1
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: 不懂, 就不要强答, 误人子弟. 写代码, 不是八股文. 要搞清楚本质. 错的答案, 比不回答. 更糟糕. |