atomic 原子操作到底有多快?我拿 Mutex 做了个对比测试 atomic 原子操作到底有多快我拿 Mutex 做了个对比测试前言写并发代码锁是免不了的。Mutex 好用但确实慢。高并发场景atomic 原子操作是个好东西但很多人不知道怎么用对。今天我拿两百万次并发操作做了个测试结果真的差很远。一、底层原理1.1 atomic 到底是怎么工作的atomic 原子操作利用 CPU 指令级别的支持确保内存操作的原子性graph TD A[多个协程同时写] -- B[CPU 内存总线] B -- C[Mutex: 操作系统锁] B -- D[Atomic: CPU 指令锁] C -- E[用户态/内核态切换] D -- F[硬件级别保证] E -- G[耗时: 微秒级] F -- H[耗时: 纳秒级]关键点Mutex 涉及系统调用昂贵atomic 直接调用 CPU 指令atomic 不会阻塞协程调度从 GMP 角度看atomic 不影响 P 的运行队列1.2 atomic vs Mutex 对比维度atomicMutex差距速度纳秒级微秒级100倍协程阻塞不阻塞阻塞显著适用场景简单计数器复杂临界区-使用难度低低-二、快速上手直接看代码对比package main import ( fmt sync sync/atomic time ) var ( mutexCount int64 atomicCount int64 mu sync.Mutex ) func testMutex(wg *sync.WaitGroup) { defer wg.Done() for i : 0; i 100000; i { mu.Lock() mutexCount mu.Unlock() } } func testAtomic(wg *sync.WaitGroup) { defer wg.Done() for i : 0; i 100000; i { atomic.AddInt64(atomicCount, 1) } } func main() { var wg sync.WaitGroup n : 100 start : time.Now() for i : 0; i n; i { wg.Add(1) go testMutex(wg) } wg.Wait() fmt.Printf(Mutex: %v, count: %d\n, time.Since(start), mutexCount) atomicCount 0 start time.Now() for i : 0; i n; i { wg.Add(1) go testAtomic(wg) } wg.Wait() fmt.Printf(Atomic: %v, count: %d\n, time.Since(start), atomicCount) }在我的机器上跑atomic 快了至少 10 倍。三、核心 API / 深水区3.1 atomic 操作速查函数功能注意事项AddInt64原子加对齐要求LoadInt64原子读防止乱序StoreInt64原子写防止乱序CompareAndSwapCAS乐观锁Swap交换返回旧值3.2 原子操作必须对齐这个在内存对齐那篇说过这里再强调一次type BadCounter struct { flag byte count int64 // 没对齐 } type GoodCounter struct { count int64 // 对齐了 flag byte }3.3 CAS 乐观锁原理CAS 是 Compare And Swap先比较再替换var value int64 func update(newValue int64) { for { old : atomic.LoadInt64(value) if atomic.CompareAndSwapInt64(value, old, newValue) { return } // 失败就重试 } }四、实战演练用 atomic 实现高性能计数器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) } type MutexCounter struct { mu sync.Mutex count int64 } func (c *MutexCounter) Inc() { c.mu.Lock() c.count c.mu.Unlock() } func (c *MutexCounter) Dec() { c.mu.Lock() c.count-- c.mu.Unlock() } func (c *MutexCounter) Value() int64 { c.mu.Lock() defer c.mu.Unlock() return c.count } func main() { var wg sync.WaitGroup ac : AtomicCounter{} mc : MutexCounter{} start : time.Now() for i : 0; i 50; i { wg.Add(1) go func() { defer wg.Done() for j : 0; j 200000; j { ac.Inc() } }() } wg.Wait() fmt.Printf(Atomic: %v, value: %d\n, time.Since(start), ac.Value()) start time.Now() for i : 0; i 50; i { wg.Add(1) go func() { defer wg.Done() for j : 0; j 200000; j { mc.Inc() } }() } wg.Wait() fmt.Printf(Mutex: %v, value: %d\n, time.Since(start), mc.Value()) }五、避坑指南与最佳实践 **技巧读也加 Load 不是白加的不加 Load 可能读到旧值因为 CPU 乱序执行。⚠️ **警告atomic 不能替代 Mutex复杂的临界区还得上 Mutex。✅ **推荐简单计数器用 atomic高频场景atomic 是你的朋友。六、综合实战演示生产级并发限流器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 和 Mutex 各有各的用法简单计数用 atomic复杂临界区用 Mutexatomic 快但不万能注意内存对齐选对工具性能翻倍。