跳转到内容

Go 原子操作

来自代码酷

模板:编程语言学习路径/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  
		}  
	}  
}

性能对比[编辑 | 编辑源代码]

原子操作与互斥锁的性能差异可通过以下场景对比:

barChart title 原子操作 vs 互斥锁吞吐量(ops/ms) x-axis 方法 y-axis 吞吐量 series "高并发" "atomic": 850 "mutex": 120

实际应用场景[编辑 | 编辑源代码]

1. 计数器统计:如Web服务器的请求计数。 2. 标志位控制:如优雅关闭服务的信号标记。 3. 无锁队列:通过CAS实现线程安全的队列。

数学原理[编辑 | 编辑源代码]

原子操作的底层实现依赖硬件指令,如CAS的数学表达为: CAS(addr,old,new)={trueif *addr=old then *addrnewfalseotherwise

注意事项[编辑 | 编辑源代码]

  • ABA问题:CAS可能因值被多次修改后还原而误判,需配合版本号解决。
  • 适用范围有限:复杂结构仍需依赖`sync.Mutex`或`channel`。
  • 内存顺序:Go的`atomic`包默认保证顺序一致性,但不同平台行为可能差异。

进阶阅读建议[编辑 | 编辑源代码]

  • 研究`runtime/internal/atomic`包的平台相关实现。
  • 了解CPU缓存行(Cache Line)与原子操作的关系。