Go语言中的Atomic:无锁编程的艺术
Go语言中的Atomic无锁编程的艺术写了十几年代码的Go后端老兵。今天聊聊atomic这个无锁编程的神器。一、为什么需要Atomic上周我们优化一个计数器用Mutex保护结果性能瓶颈就在这把锁上。换成atomic后QPS提升了3倍。这就是atomic的威力无锁、高性能、线程安全。二、Atomic的基本用法1. 原子操作类型import sync/atomic // 整数类型 var counter int64 atomic.AddInt64(counter, 1) // 原子加 atomic.LoadInt64(counter) // 原子读 atomic.StoreInt64(counter, 100) // 原子写 // 指针类型 var ptr unsafe.Pointer atomic.StorePointer(ptr, unsafe.Pointer(new(int))) atomic.LoadPointer(ptr) // 32位整数 var count32 int32 atomic.AddInt32(count32, 1)2. CAS操作func casDemo() { var value int64 100 // 如果value等于100就改为200 swapped : atomic.CompareAndSwapInt64(value, 100, 200) fmt.Println(swapped) // true fmt.Println(value) // 200 // 如果value等于100就改为300不会成功 swapped atomic.CompareAndSwapInt64(value, 100, 300) fmt.Println(swapped) // false fmt.Println(value) // 200 }三、Atomic的实战技巧1. 高性能计数器type AtomicCounter struct { count atomic.Int64 } func (c *AtomicCounter) Increment() { c.count.Add(1) } func (c *AtomicCounter) Get() int64 { return c.count.Load() } // 对比Mutex版本 type MutexCounter struct { mu sync.Mutex count int64 } func (c *MutexCounter) Increment() { c.mu.Lock() defer c.mu.Unlock() c.count }2. 无锁队列type Node struct { value int next unsafe.Pointer } type LockFreeQueue struct { head unsafe.Pointer tail unsafe.Pointer } func NewLockFreeQueue() *LockFreeQueue { dummy : Node{} return LockFreeQueue{ head: unsafe.Pointer(dummy), tail: unsafe.Pointer(dummy), } } func (q *LockFreeQueue) Enqueue(value int) { newNode : Node{value: value} for { tail : (*Node)(atomic.LoadPointer(q.tail)) next : (*Node)(atomic.LoadPointer(tail.next)) if tail (*Node)(atomic.LoadPointer(q.tail)) { if next nil { if atomic.CompareAndSwapPointer(tail.next, unsafe.Pointer(next), unsafe.Pointer(newNode)) { atomic.CompareAndSwapPointer(q.tail, unsafe.Pointer(tail), unsafe.Pointer(newNode)) return } } else { atomic.CompareAndSwapPointer(q.tail, unsafe.Pointer(tail), unsafe.Pointer(next)) } } } }3. 状态标志type Server struct { running atomic.Bool } func (s *Server) Start() { if !s.running.CompareAndSwap(false, true) { return // 已经在运行 } // 启动逻辑 } func (s *Server) Stop() { if !s.running.CompareAndSwap(true, false) { return // 已经停止 } // 停止逻辑 } func (s *Server) IsRunning() bool { return s.running.Load() }四、Atomic的高级用法1. 原子指针type Config struct { Timeout time.Duration MaxConn int } var config atomic.Value func LoadConfig() *Config { return config.Load().(*Config) } func UpdateConfig(c *Config) { config.Store(c) } func init() { config.Store(Config{ Timeout: 30 * time.Second, MaxConn: 100, }) }2. 无锁栈type Stack struct { top unsafe.Pointer } type stackNode struct { value int next unsafe.Pointer } func (s *Stack) Push(value int) { newNode : stackNode{value: value} for { oldTop : atomic.LoadPointer(s.top) newNode.next oldTop if atomic.CompareAndSwapPointer(s.top, oldTop, unsafe.Pointer(newNode)) { return } } } func (s *Stack) Pop() (int, bool) { for { oldTop : atomic.LoadPointer(s.top) if oldTop nil { return 0, false } node : (*stackNode)(oldTop) newTop : node.next if atomic.CompareAndSwapPointer(s.top, oldTop, newTop) { return node.value, true } } }五、Atomic vs Mutex场景推荐方案原因简单计数器atomic性能更好复杂数据结构Mutex实现简单读多写少RWMutex并发读性能无锁算法atomic极致性能六、性能对比func BenchmarkAtomic(b *testing.B) { var counter atomic.Int64 b.RunParallel(func(pb *testing.PB) { for pb.Next() { counter.Add(1) } }) } func BenchmarkMutex(b *testing.B) { var mu sync.Mutex var counter int64 b.RunParallel(func(pb *testing.PB) { for pb.Next() { mu.Lock() counter mu.Unlock() } }) } // 结果Atomic比Mutex快5-10倍七、常见陷阱1. 误用atomic操作复杂类型// 错误atomic不能操作复杂类型 type User struct { Name string Age int } var user atomic.Value // 正确使用指针 user.Store(User{Name: Alice, Age: 30}) u : user.Load().(*User)2. ABA问题// 经典ABA问题 // 线程1读取A // 线程2A-B-A // 线程1CAS成功但A已经不是原来的A // 解决方案使用版本号 type VersionedPointer struct { ptr unsafe.Pointer ver int64 }3. 内存序问题// Go的atomic保证顺序一致性 // 不需要像C那样担心内存序 var flag atomic.Bool var data int func writer() { data 42 flag.Store(true) } func reader() { if flag.Load() { fmt.Println(data) // 保证看到42 } }八、总结atomic是无锁编程的基础用好它可以实现极致的性能优化避免锁带来的开销构建无锁数据结构记住能跑就行别折腾。但该用atomic的时候一定要了解其原理。

相关新闻

最新新闻

日新闻

周新闻

月新闻