Golang Atomic原子操作
在Golang中,使用atomic包进行原子操作时,为什么有时候性能比Mutex更好?具体哪些场景适合用atomic而不是Mutex?atomic.Value和普通的atomic操作有什么区别?能否举例说明在实际项目中如何正确使用atomic来避免竞态条件?
2 回复
Golang的atomic包提供原子操作,用于并发安全地读写变量,避免数据竞争。常用方法如Add、Load、Store、Swap等,适用于计数器、标志位等场景。比互斥锁更轻量,但功能有限。
更多关于Golang Atomic原子操作的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go语言中,atomic包提供了底层的原子级内存操作,用于实现无锁的并发控制,避免数据竞争。它适用于对基本数据类型(如int32、int64、uint32等)进行简单的读写或修改操作,比使用互斥锁(sync.Mutex)更高效,但功能有限。
主要函数
- 加载(Load):原子性地读取值。
LoadInt32(addr *int32) int32
- 存储(Store):原子性地写入值。
StoreInt32(addr *int32, val int32)
- 加法(Add):原子性地增加值。
AddInt32(addr *int32, delta int32) int32
- 比较并交换(CompareAndSwap, CAS):仅在当前值等于旧值时更新为新值。
CompareAndSwapInt32(addr *int32, old, new int32) bool
- 交换(Swap):原子性地设置新值并返回旧值。
SwapInt32(addr *int32, new int32) int32
示例代码
以下是一个使用atomic实现计数器的简单示例:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var counter int32
var wg sync.WaitGroup
// 启动多个goroutine并发增加计数器
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
atomic.AddInt32(&counter, 1)
wg.Done()
}()
}
wg.Wait()
fmt.Println("Final counter:", atomic.LoadInt32(&counter)) // 输出: Final counter: 1000
}
注意事项
- 适用场景:仅用于简单的整数或指针操作。复杂数据结构需用
sync.Mutex或sync.RWMutex。 - 性能:在高度竞争环境下,
atomic通常比锁更快,但非竞争时可能因内存屏障而稍慢。 - 内存顺序:Go的
atomic操作保证顺序一致性,无需手动管理内存屏障。
通过合理使用atomic,可以提升并发程序的性能和可靠性。

