Go CAS比较并交换操作 - Golang原子操作详解
CAS(Compare-And-Swap)是实现无锁并发的核心原语。掌握CAS操作对于编写高性能并发代码至关重要。
📋 CAS核心概念
CAS操作原理
CAS是一种原子操作,包含三个操作数:内存位置V、预期值A和新值B。只有当V的值等于A时,才会将V更新为B。
go
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
func main() {
fmt.Println("=== Go CAS比较并交换操作 ===")
// 1. 基础CAS操作
fmt.Printf("\n--- 基础CAS操作 ---\n")
var value int32 = 100
fmt.Printf("初始值: %d\n", value)
// CAS操作:如果值为100,则更新为200
swapped := atomic.CompareAndSwapInt32(&value, 100, 200)
fmt.Printf("CAS(100->200): %t, 当前值: %d\n", swapped, value)
// 再次CAS:预期值不匹配,不会更新
swapped = atomic.CompareAndSwapInt32(&value, 100, 300)
fmt.Printf("CAS(100->300): %t, 当前值: %d\n", swapped, value)
// 2. 无锁计数器
fmt.Printf("\n--- 无锁计数器 ---\n")
type LockFreeCounter struct {
value int64
}
func (c *LockFreeCounter) Increment() int64 {
for {
old := atomic.LoadInt64(&c.value)
new := old + 1
if atomic.CompareAndSwapInt64(&c.value, old, new) {
return new
}
// CAS失败,重试
}
}
func (c *LockFreeCounter) Get() int64 {
return atomic.LoadInt64(&c.value)
}
counter := &LockFreeCounter{}
var wg sync.WaitGroup
// 并发增加
goroutines := 100
increments := 1000
start := time.Now()
for i := 0; i < goroutines; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < increments; j++ {
counter.Increment()
}
}()
}
wg.Wait()
elapsed := time.Since(start)
expected := int64(goroutines * increments)
actual := counter.Get()
fmt.Printf("期望值: %d\n", expected)
fmt.Printf("实际值: %d\n", actual)
fmt.Printf("正确性: %t\n", expected == actual)
fmt.Printf("耗时: %v\n", elapsed)
// 3. 无锁栈
fmt.Printf("\n--- 无锁栈 ---\n")
type LockFreeStack struct {
head unsafe.Pointer
}
type node struct {
value int
next unsafe.Pointer
}
func NewLockFreeStack() *LockFreeStack {
return &LockFreeStack{}
}
func (s *LockFreeStack) Push(v int) {
newNode := &node{value: v}
for {
oldHead := atomic.LoadPointer(&s.head)
newNode.next = oldHead
if atomic.CompareAndSwapPointer(&s.head, oldHead, unsafe.Pointer(newNode)) {
return
}
}
}
func (s *LockFreeStack) Pop() (int, bool) {
for {
oldHead := atomic.LoadPointer(&s.head)
if oldHead == nil {
return 0, false
}
headNode := (*node)(oldHead)
newHead := headNode.next
if atomic.CompareAndSwapPointer(&s.head, oldHead, newHead) {
return headNode.value, true
}
}
}
stack := NewLockFreeStack()
// 并发Push
for i := 0; i < 10; i++ {
wg.Add(1)
go func(val int) {
defer wg.Done()
stack.Push(val)
}(i)
}
wg.Wait()
// Pop所有元素
fmt.Printf("Pop元素: ")
for {
val, ok := stack.Pop()
if !ok {
break
}
fmt.Printf("%d ", val)
}
fmt.Println()
// 4. 性能对比
fmt.Printf("\n--- 性能对比:CAS vs Mutex ---\n")
iterations := 1000000
// CAS版本
var casCounter int64
start = time.Now()
for i := 0; i < iterations; i++ {
atomic.AddInt64(&casCounter, 1)
}
casTime := time.Since(start)
// Mutex版本
var mutexCounter int64
var mu sync.Mutex
start = time.Now()
for i := 0; i < iterations; i++ {
mu.Lock()
mutexCounter++
mu.Unlock()
}
mutexTime := time.Since(start)
fmt.Printf("CAS版本: %v\n", casTime)
fmt.Printf("Mutex版本: %v\n", mutexTime)
fmt.Printf("性能提升: %.2fx\n", float64(mutexTime)/float64(casTime))
fmt.Printf("\n🎯 CAS使用建议:\n")
fmt.Printf("1. 适用于简单的原子更新操作\n")
fmt.Printf("2. 高竞争下可能频繁重试\n")
fmt.Printf("3. 无锁不等于无等待\n")
fmt.Printf("4. 复杂逻辑建议使用Mutex\n")
fmt.Printf("5. 注意ABA问题\n")
fmt.Printf("\n📋 常用原子操作:\n")
fmt.Printf("- atomic.CompareAndSwapInt32/64\n")
fmt.Printf("- atomic.CompareAndSwapPointer\n")
fmt.Printf("- atomic.AddInt32/64\n")
fmt.Printf("- atomic.LoadInt32/64\n")
fmt.Printf("- atomic.StoreInt32/64\n")
}
import "unsafe"🎯 核心知识点总结
CAS操作特点
- 原子性: 操作不可分割,要么成功要么失败
- 无锁: 不需要互斥锁,避免了锁开销
- 重试机制: 失败时需要重试直到成功
- 适用场景: 简单的原子更新操作
无锁数据结构
- 无锁计数器: 使用CAS实现线程安全的计数
- 无锁栈: 基于CAS的并发栈实现
- 无锁队列: 更复杂的无锁数据结构
- 性能优势: 在低竞争下性能优于锁
注意事项
- ABA问题: 值可能被修改后又改回
- 重试开销: 高竞争下重试次数多
- 适用范围: 不是所有场景都适合CAS
- 正确性: 确保CAS循环的正确性
性能对比
- 低竞争: CAS显著优于Mutex
- 高竞争: Mutex可能更优
- 简单操作: CAS是首选
- 复杂临界区: 建议使用Mutex
🔍 面试准备建议
- 原理理解: 深入理解CAS的硬件实现
- 应用场景: 掌握何时使用CAS
- 性能分析: 了解CAS的性能特征
- 问题处理: 理解ABA等常见问题
- 实践经验: 积累无锁编程经验
