Golang CAS算法原理与应用
Golang中的CAS算法(Compare And Swap)
CAS(Compare And Swap,比较并交换)是一种无锁编程中常用的原子操作,Golang通过sync/atomic包提供了对CAS的支持。
CAS基本概念
CAS操作包含三个操作数:
- 内存位置(V)
- 预期原值(A)
- 新值(B)
CAS操作逻辑:
如果内存位置V的值等于预期原值A,则将位置V的值修改为新值B,否则不做任何操作
Golang中的CAS实现
在Go中,主要使用atomic.CompareAndSwap系列函数:
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)
func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)
func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)
func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)
func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool)
使用示例
基本使用
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var value int32 = 10
// 尝试将value从10改为20
swapped := atomic.CompareAndSwapInt32(&value, 10, 20)
fmt.Println("Swapped:", swapped, "Value:", value) // Swapped: true Value: 20
// 再次尝试将value从10改为30(会失败,因为当前值已经是20)
swapped = atomic.CompareAndSwapInt32(&value, 10, 30)
fmt.Println("Swapped:", swapped, "Value:", value) // Swapped: false Value: 20
}
实现自旋锁
package main
import (
"fmt"
"sync/atomic"
"time"
)
type SpinLock struct {
flag int32
}
func (sl *SpinLock) Lock() {
for !atomic.CompareAndSwapInt32(&sl.flag, 0, 1) {
// 自旋等待
time.Sleep(time.Nanosecond)
}
}
func (sl *SpinLock) Unlock() {
atomic.StoreInt32(&sl.flag, 0)
}
func main() {
var lock SpinLock
var counter int
for i := 0; i < 100; i++ {
go func() {
lock.Lock()
counter++
lock.Unlock()
}()
}
time.Sleep(time.Second)
fmt.Println("Counter:", counter) // 应该输出100
}
CAS的优缺点
优点
- 无锁操作,避免线程阻塞和上下文切换
- 适用于竞争不激烈的场景,性能较高
缺点
- ABA问题:值可能从A变为B又变回A,CAS会误认为没有变化
- 自旋时间长会消耗CPU资源
- 只能保证一个共享变量的原子操作
解决ABA问题
Go中可以使用atomic.Value或版本号等方式解决ABA问题:
type ABA struct {
value int32
version int32
}
func (a *ABA) Update(newValue int32) {
for {
oldValue := atomic.LoadInt32(&a.value)
oldVersion := atomic.LoadInt32(&a.version)
if atomic.CompareAndSwapInt32(&a.value, oldValue, newValue) {
atomic.CompareAndSwapInt32(&a.version, oldVersion, oldVersion+1)
break
}
}
}
总结
CAS是Go中实现无锁并发编程的重要工具,合理使用可以提升程序性能,但也需要注意其局限性和潜在问题。
Do not communicate by sharing memory; instead, share memory by communicating.

浙公网安备 33010602011771号