Go 原子操作
外观
概述[编辑 | 编辑源代码]
原子操作(Atomic Operations)是并发编程中保证共享资源线程安全的核心机制之一。在Go语言中,`sync/atomic`包提供了一组底层原子操作函数,用于在不使用互斥锁的情况下对基本数据类型(如整型、指针)进行线程安全的读写。原子操作通过硬件级指令(如CAS, Compare-And-Swap)确保操作的不可分割性,适用于高性能场景。
核心特性[编辑 | 编辑源代码]
- 不可分割性:操作要么完全执行,要么完全不执行,不会被线程调度打断。
- 无锁设计:相比互斥锁(`sync.Mutex`),原子操作通常性能更高。
- 有限数据类型支持:仅支持`int32`、`int64`、`uint32`、`uint64`、`uintptr`和指针类型。
常用函数[编辑 | 编辑源代码]
以下是`sync/atomic`包的核心函数:
函数签名 | 描述 |
---|---|
`func AddT(addr *T, delta T)` | 原子地增加/减少值 |
`func LoadT(addr *T) T` | 原子地读取值 |
`func StoreT(addr *T, val T)` | 原子地写入值 |
`func SwapT(addr *T, new T) T` | 原子交换新旧值 |
`func CompareAndSwapT(addr *T, old, new T) bool` | CAS操作,仅在当前值等于`old`时交换 |
代码示例[编辑 | 编辑源代码]
基础计数器[编辑 | 编辑源代码]
以下示例展示如何通过原子操作实现线程安全的计数器:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var counter int32
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
atomic.AddInt32(&counter, 1)
wg.Done()
}()
}
wg.Wait()
fmt.Println("Counter:", counter) // 输出: Counter: 1000
}
CAS操作实战[编辑 | 编辑源代码]
Compare-And-Swap(CAS)是原子操作的典型应用,常用于实现无锁数据结构:
func atomicUpdate(addr *int32, target int32) {
for {
old := atomic.LoadInt32(addr)
if atomic.CompareAndSwapInt32(addr, old, old+target) {
break
}
}
}
性能对比[编辑 | 编辑源代码]
原子操作与互斥锁的性能差异可通过以下场景对比:
实际应用场景[编辑 | 编辑源代码]
1. 计数器统计:如Web服务器的请求计数。 2. 标志位控制:如优雅关闭服务的信号标记。 3. 无锁队列:通过CAS实现线程安全的队列。
数学原理[编辑 | 编辑源代码]
原子操作的底层实现依赖硬件指令,如CAS的数学表达为:
注意事项[编辑 | 编辑源代码]
- ABA问题:CAS可能因值被多次修改后还原而误判,需配合版本号解决。
- 适用范围有限:复杂结构仍需依赖`sync.Mutex`或`channel`。
- 内存顺序:Go的`atomic`包默认保证顺序一致性,但不同平台行为可能差异。
进阶阅读建议[编辑 | 编辑源代码]
- 研究`runtime/internal/atomic`包的平台相关实现。
- 了解CPU缓存行(Cache Line)与原子操作的关系。