Go 读取全局变量要加锁?!

2019-03-13 16:48:33 +08:00
 index90

在看同事的代码时候,发现这样的操作:

var (
  object = New()
  mu = sync.RWMutex
)

func SetValue(v SomeInterface) {
  mu.Lock()
  object = v
  mu.Unlock()
}

func GetValue() SomeInterface {
  mu.RLock()
  defer mu.RUnlock()
  return object
}  

为什么要加读锁啊?!难道会 Get 到 nil ? 同事给了我这个链接: https://stackoverflow.com/questions/21447463/is-assigning-a-pointer-atomic-in-golang

10782 次点击
所在节点    Go 编程语言
51 条回复
qiyuey
2019-03-13 19:32:50 +08:00
指令重排序?
hilbertz
2019-03-13 19:36:27 +08:00
如果是 x86 平台,那加不加锁都没什么关系
janxin
2019-03-13 19:36:50 +08:00
你只要知道你这么写会出现什么问题导致什么结果并且你觉得没问题 /业务不会出现问题就怎么写都行
gamexg
2019-03-13 20:19:52 +08:00
目前有性能问题?
即使有性能问题也不建议移除锁,换成原子操作更好些。

官方文档未声明安全就不要这么做,鬼知道之后会是什么情况。
另外移除锁自动化测试时会报竟态冲突,过不了测试了。
fengjianxinghun
2019-03-13 20:41:33 +08:00
https://golang.org/src/sync/atomic/value.go

看看官方的 interface{}原子操作要做多少工作
ms2008
2019-03-13 21:37:45 +08:00
blless
2019-03-13 21:52:48 +08:00
看场景吧,大部分全局变量都是直接读…除非会导致业务脏数据才需要锁配合
fengjianxinghun
2019-03-13 23:00:54 +08:00
@keakon 单 cpu 可以有这种保证,smp 下就不行了,得汇编 lock 指令总线,这也是原子 atomic 得由来
reus
2019-03-13 23:39:39 +08:00
当然要加锁啊,interface 是一个指针一个类型,哪里能保证读写的原子性
何况除了原子性还有指令乱序,你不加锁,分分钟给你优化出一些会炸的顺序
死锁都好过竞态啊
何况需要保证质量时,都会开 -race 做测试,你这种并发读写的,肯定报错的
这都常识,又哪个“高级语言”不需要理解这个的?不要认为自己不懂的就叫底层!
yanaraika
2019-03-13 23:51:12 +08:00
9102 年还有人 x86 不明确加锁 /atomic 读写 64 位变量?原子性是一回事,编译器重排、指令乱序、acquire-release 语义了解一下
mornlight
2019-03-14 00:28:45 +08:00
的确会有 data race 的问题,带 -race 跑一下代码就知道了: https://play.golang.org/p/GQ5FXw7jXe0
zkeeper
2019-03-14 06:10:41 +08:00
没觉得你同事的代码有问题, 很正常的操作. 反倒是楼上很多同学对线程安全一知半解或者漠不关心. 到时候出了奇怪的 bug 没法有规律的复现等着哭去吧
vindurriel
2019-03-14 07:12:25 +08:00
另一个角度 避免用全局变量 非要用还不加锁 这是在养 bug
index90
2019-03-14 09:58:40 +08:00
@reus 一直以为赋值表达式就是原子的,看来我才疏学浅,让大神见笑了
cloudzhou
2019-03-14 10:05:18 +08:00
@lihongjie0209 你的说法也是对的,我一直和人说如何写好并发相关代码,那就是“尽量避免并发”
但是从这里来看,那就是需要的
keakon
2019-03-14 10:21:47 +08:00
@fengjianxinghun 没关系的,需求是可以获取旧值,只要不获取到错误的值就行
index90
2019-03-14 10:22:52 +08:00
@cloudzhou 想再请教一个问题,例如我要实现一个 rpc service,我实现了一个 business struct。每个请求进来后,我要 new 一个业务逻辑对象去处理请求?还是只实例化一个对象,然后传入对象指针给每个 gorouting 去处理呢?类似的问题一般要考虑哪些点?
zarte
2019-03-14 10:22:59 +08:00
越看越糊涂。。
首先例子既然不用考虑旧数据问题加不加锁都不影响吧。
其次 a=b 这样是原子的吧又不是 a=b+c
index90
2019-03-14 10:26:31 +08:00
@zarte 颠覆认知了吧,前面大神说了,几乎没有语言能够保证,赋值是原子的。注意,这里说的是保证。
zarte
2019-03-14 10:28:42 +08:00
@index90 不可能吧。b+c 是因为汇编是多步的原因。

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

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

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

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

© 2021 V2EX