TL;DR:有必要
前几天公司内论坛有人提了这么一个问题:
看了一遍 atomic 源码,没有理解
atomic.Value
的使用场景,网上的用法基本上都是用在配置更新上,感觉我用 machine word 原子读写也能保证原子性,那为啥还要有atomc.Value呢
然后贴了一段代码,大致的逻辑是这样
package main
import (
"time"
)
type Config struct {
Name string
Age int
}
func main() {
conf := &Config{
Name: "foo", Age: 10}
go func() {
for {
time.Sleep(time.Second)
conf = &Config{
Name: "bar", Age: 20}
println("new config:", conf.Name, conf.Age)
}
}()
for {
time.Sleep(time.Second)
println("current config:", conf.Name, conf.Age)
}
}
他在第 18 行 conf = &Config{Name: "bar", Age: 20}
,通过指针赋值
的方式替换了conf变量。
不仔细想好像确实没毛病:uintptr 替换,一条指令就搞完了,操作是原子的。
分析操作背景
上面操作主要面向的是多 goroutine 针对同一个变量进行读写。按照管用的套路先上 data race detector
看看工具分析结果。结果很明显,确实存在 data race
如果换成 atomic.Value
就没有告警
package main
import (
"sync/atomic"
"time"
)
type Config struct {
Name string
Age int
}
func main() {
conf := atomic.Value{
}
conf.Store(&Config{
Name: "foo", Age: 10})
go func() {
for {
time.Sleep(time.Second)
conf.Store(&Config{
Name: "bar", Age: 20})
t := conf.Load(