go 源码困惑, 在 once.Do 中放标志变量,还是放操作本身。

59 天前
 SGL
func AfterFunc(ctx Context, f func()) (stop func() bool) {
a := &afterFuncCtx{
f: f,
}
a.cancelCtx.propagateCancel(ctx, a)
return func() bool {
stopped := false
a.once.Do(func() {
stopped = true
})
if stopped { // TODO: 这个代码我很费解, 为什么不把 a.cancel(true, Canceled, nil)操作直接放到 once.Do 中呢。
a.cancel(true, Canceled, nil)
}
return stopped
}
}

这个是 go 源码中 context 包的部分代码。我很奇怪,为什么不在匿名函数中直接调用 a.once.Do(func(){ a.cancel(true, Canceled,nil)}), 这样也能确保这个取消操作只执行一次啊, 为什么要维护一个局部的标志变量呢。
1986 次点击
所在节点    Go 编程语言
5 条回复
cloudzhou
59 天前
是可以的,这个和个人代码风格有关,go 源代码的写法,stopped 变量作为一个独立的逻辑,后面以此作为判断,比较清晰
ihciah
59 天前
这很 golang🌚外面一个 once ,cancel 里面还一个 atomic ,可能放这儿是避免给人一种复制的时候狂点 ctrl c 增大复制成功概率的感觉。
lovelylain
58 天前
要看全啊,仅看这里我的感觉是用 atomic.Bool 也能保证 stop 仅 1 次,为什么要用 sync.Once 。找来源码一看,这里是通过 sync.Once 仅执行 1 次实现要么调用 f 要么取消,调用 f 在 cancel 函数里,stop 后也会调用 cancel ,如果把 cancel 也放在 once 里调用,就可能死锁了。
liaohongxing
58 天前
看函数签名 ,主要为了返回一个 bool 值吧 !把 stopped 这个变量 return 了 ,直接 cancel 没法返回这个布尔值。
jigujigushanshan
58 天前
就是代码风格而已,比较明了,逻辑是逻辑,变量是变量 就算你写 once 里面了如果后面改 stop 还能因为其他原因变为 true 你不是还得把执行 cancel 移到外面来吗

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1145175

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX