在 Ants 的源码中,internal/sync/spinlock.go
实现了一个自旋锁。通过指数退避算法递增 goroutine 在获取锁失败后的等待时间,来减少资源的争用并提高重试的成功率。
Ants 采用 uint32
这种简单类型作为自旋锁的实现基础,并通过对该变量进行原子操作以确保线程安全。此外,使用 maxBackoff
常量来限制最大的重试等待时间。
type spinLock uint32
const maxBackoff = 16
加锁
在每次尝试加锁时,首先将 backoff
的值初始化为 1
。每次获取锁失败后,backoff
的值会翻倍。如果 CAS 操作失败,goroutine 进入循环,在循环中,它会连续调用 runtime.Gosched()
backoff
次,以此让出 CPU 时间片。当成功获取锁时,spinLock
的值会被设置为 1
。
func (sl *spinLock) Lock() {
backoff := 1
for !atomic.CompareAndSwapUint32((*uint32)(sl), 0, 1) {
for i := 0; i < backoff; i++ {
runtime.Gosched()
}
if backoff < maxBackoff {
backoff <<= 1
}
}
}
释放锁
释放锁的操作相对简单。通过调用 atomic.StoreUint32()
方法,spinLock
会被原子地设置为 0
,从而释放锁。
func (sl *spinLock) Unlock() {
atomic.StoreUint32((*uint32)(sl), 0)
}