atomic 原子操作真的“原子“吗?CPU 指令真相解析

发布时间:2026/6/6 7:42:50

atomic 原子操作真的“原子“吗?CPU 指令真相解析 atomic 原子操作真的原子吗CPU 指令真相解析前言atomic 包是 Go 并发编程的利器速度快、无锁、不阻塞。但很多人不知道atomic 操作在底层是怎么实现的。atomic 操作真的原子吗本文研究了 CPU 指令后发现有些操作是真正的原子有些只是看起来原子。今天来聊聊。一、 底层原理1.1 atomic 的底层实现atomic 操作依赖 CPU 的原子指令graph TD A[atomic.AddInt64] -- B[CPU 指令] B -- C[LOCK 前缀] C -- D[内存总线锁定] D -- E[原子操作] E -- F[返回新值] G[CAS] -- H[比较并交换] H -- I[原子指令] I -- J[成功或失败]关键点LOCK 前缀确保指令原子性内存总线锁定影响其他 CPUCAS 是无锁编程的基础不同 CPU 架构实现不同1.2 atomic 操作分类操作指令原子性性能AddInt64LOCK XADD真原子快LoadInt64LOCK MOV真原子快StoreInt64LOCK MOV真原子快CompareAndSwapLOCK CMPXCHG真原子中SwapLOCK XCHG真原子快二、 快速上手2.1 atomic 的基本使用package main import ( fmt sync sync/atomic ) var count int64 func main() { var wg sync.WaitGroup for i : 0; i 100; i { wg.Add(1) go func() { defer wg.Done() for j : 0; j 100000; j { atomic.AddInt64(count, 1) } }() } wg.Wait() fmt.Printf(count: %d\n, count) }2.2 atomic 与 Mutex 对比import ( sync sync/atomic time ) var ( atomicCount int64 mutexCount int64 mu sync.Mutex ) func atomicInc() { atomic.AddInt64(atomicCount, 1) } func mutexInc() { mu.Lock() mutexCount mu.Unlock() } func main() { n : 10000000 start : time.Now() for i : 0; i n; i { atomicInc() } fmt.Printf(atomic: %v\n, time.Since(start)) start time.Now() for i : 0; i n; i { mutexInc() } fmt.Printf(mutex: %v\n, time.Since(start)) }三、 核心 API / 深水区3.1 atomic 操作速查函数功能注意事项AddInt64原子加对齐要求LoadInt64原子读防止乱序StoreInt64原子写防止乱序CompareAndSwapCAS乐观锁Swap交换返回旧值3.2 内存对齐要求// 错误没有对齐 type BadCounter struct { flag byte count int64 // 可能没对齐 } // 正确保证对齐 type GoodCounter struct { count int64 // 8 字节对齐 flag byte }3.3 CAS 乐观锁实现var value int64 func update(newValue int64) bool { for { old : atomic.LoadInt64(value) if atomic.CompareAndSwapInt64(value, old, newValue) { return true } // 失败重试 } }四、 实战演练4.1 高性能计数器package main import ( fmt sync sync/atomic time ) type AtomicCounter struct { count int64 } func (c *AtomicCounter) Inc() { atomic.AddInt64(c.count, 1) } func (c *AtomicCounter) Dec() { atomic.AddInt64(c.count, -1) } func (c *AtomicCounter) Value() int64 { return atomic.LoadInt64(c.count) } func main() { counter : AtomicCounter{} var wg sync.WaitGroup start : time.Now() for i : 0; i 100; i { wg.Add(1) go func() { defer wg.Done() for j : 0; j 100000; j { counter.Inc() } }() } wg.Wait() fmt.Printf(耗时: %v, count: %d\n, time.Since(start), counter.Value()) }五、 避坑指南与最佳实践技巧读操作也用 Load不加 Load 可能读到旧值因为 CPU 乱序执行。⚠️警告atomic 不能替代 Mutex复杂临界区还得上 Mutex。✅推荐简单计数器用 atomic高频场景atomic 是你的朋友。六、 综合实战演示6.1 生产级并发限流器package main import ( fmt sync sync/atomic time ) type RateLimiter struct { limit int64 current int64 interval time.Duration lastTime time.Time } func NewRateLimiter(limit int64, interval time.Duration) *RateLimiter { return RateLimiter{ limit: limit, interval: interval, lastTime: time.Now(), } } func (rl *RateLimiter) Allow() bool { now : time.Now() if now.Sub(rl.lastTime) rl.interval { atomic.StoreInt64(rl.current, 0) rl.lastTime now } current : atomic.AddInt64(rl.current, 1) return current rl.limit } func main() { rl : NewRateLimiter(100, time.Second) var wg sync.WaitGroup passed : int64(0) blocked : int64(0) for i : 0; i 200; i { wg.Add(1) go func() { defer wg.Done() if rl.Allow() { atomic.AddInt64(passed, 1) } else { atomic.AddInt64(blocked, 1) } }() } wg.Wait() fmt.Printf(通过: %d, 阻塞: %d\n, passed, blocked) }总结atomic 的核心要点依赖 CPU 原子指令内存对齐很重要CAS 是无锁编程基础读操作也要用 Load

相关新闻