Go中安全计数器应优先使用sync/atomic包的原子操作(如atomic.AddInt64),而非互斥锁;需用int64类型并确保字段自然对齐,所有读写必须统一使用atomic函数,避免竞态。

在 Go 中实现安全计数器,核心是避免竞态(race),关键手段是使用 sync/atomic 包提供的原子操作,而不是依赖互斥锁(sync.Mutex)——除非你需要更复杂的同步逻辑。
计数器本质是单个整型变量的增减读取。atomic 对 int32、int64、uint32、uint64、uintptr 和指针类型提供了无锁、CPU 级别的原子读写与修改,性能高、开销小、天然并发安全。
注意:必须用 int64(而非 int)配合 atomic,因为 int 在 32 位系统上是 32 位,无法保证 64 位原子性;Go 官方只对明确位宽的类型提供原子支持。
以下是一个线程安全、零依赖的计数器结构:
立即学习“go语言免费学习笔记(深入)”;
type Counter struct {
val int64
}
func (c *Counter) Add(delta int64) {
atomic.AddInt64(&c.val, delta)
}
func (c *Counter) Inc() {
atomic.AddInt64(&c.val, 1)
}
func (c *Counter) Dec() {
atomic.AddInt64(&c.val, -1)
}
func (c *Counter) Load() int64 {
return atomic.LoadInt64(&c.val)
}
func (c *Counter) Store(v int64) {
atomic.StoreInt64(&c.val, v)
}
func (c *Counter) Swap(new int64) (old int64) {
return atomic.SwapInt64(&c.val, new)
}
func (c *Counter) CompareAndSwap(old, new int64) bool {
return atomic.CompareAndSwapInt64(&c.val, old, new)
}所有方法都无需加锁,可被任意 goroutine 并发调用。例如:
c := &Counter{}
go c.Inc()
go c.Inc()
go c.Add(3)
// 最终 c.Load() == 5,无竞态int64 字段必须自然对齐(通常放在结构体开头或确保前面字段总大小是 8 的倍数),否则在某些架构(如 32 位 ARM)上 atomic 可能 panic。Go 1.19+ 已大幅缓解,但稳妥起见仍建议把 int64 放首位。atomic.LoadInt64,所有读写都必须用 atomic 函数。直接 c.val++ 会破坏原子性。CompareAndSwap 循环重试,或改用 sync.Mutex 保护临界区。math.Float64bits/math.Float64frombits 手动封装(极少必要)。当你的“计数器”行为超出原子整数能力时,例如:
这时用 sync.Mutex 封装更清晰可靠,性能差异在绝大多数场景下可忽略。
基本上就这些。用 atomic 实现计数器不复杂但容易忽略对齐和类型细节,抓住 int64 + atomic.*Int64 这个组合,就能写出高效又安全的并发计数逻辑。
以上就是如何使用Golang实现安全计数器_Golang原子操作与并发安全说明的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号