CAS(compare and swap)https://en.wikipedia.org/wiki/Compare-and-swap
Go中的sync/atomic基于CAS做到lock free。想了解下效率怎么样,写了个简单例子。
在race condition特别严重的时候,也就是两个goroutine一直在抢着修改同一个对象的时候,CAS的表现和加锁mutex的效率差不多,时高时低。 但是在没有race condition的时候,CAS的表现比mutex耗时要第一个数量级,原因也很明显,CAS在compare失败的时候回重试,所以在race严重的时候retry多,耗时偶尔炒锅mutex。但是在race没有或者小的时候,效率就体现出来了,因为没有retry,儿mutex还是需要加锁和解锁。耗时仅仅是无锁时间的两倍时间。
总结起来,多数情况下能用CAS做到lock free是比较好的,因为没有那么大量的race condition.
result:
No lock: -109178
29.617844ms
Mutex lock with condition race: 0
344.894102ms
Atomic CAS with condition race: 0
355.517159ms
Mutex lock without condition race: 10000000
179.974834ms
Atomic CAS without condition race: 10000000
54.245469ms
package main
import (
"fmt"
"sync"
"time"
"sync/atomic"
)
var wg sync.WaitGroup
var lock sync.Mutex
var times = 10000000
func add(x *int) {
for i := 0; i < times; i++ {
*x++
}
wg.Done()
}
func sub(x *int) {
for i := 0; i < times; i++ {
*x--
}
wg.Done()
}
func addMutex(x *int) {
for i := 0; i < times; i++ {
lock.Lock()
*x++
lock.Unlock()
}
wg.Done()
}
func subMutex(x *int) {
for i := 0; i < times; i++ {
lock.Lock()
*x--
lock.Unlock()
}
wg.Done()
}
func addAtomic(x *int32) {
for i := 0; i < times; i++ {
atomic.AddInt32(x, 1)
}
wg.Done()
}
func subAtomic(x *int32) {
for i := 0; i < times; i++ {
atomic.AddInt32(x, -1)
}
wg.Done()
}
func main() {
x := 0
start := time.Now()
wg.Add(2)
go add(&x)
go sub(&x)
wg.Wait()
fmt.Println("No lock: ", x)
elasped := time.Since(start)
fmt.Println(elasped)
start = time.Now()
wg.Add(2)
x = 0
go addMutex(&x)
go subMutex(&x)
wg.Wait()
fmt.Println("Mutex lock with condition race: ", x)
elasped = time.Since(start)
fmt.Println(elasped)
start = time.Now()
wg.Add(2)
var y int32 = 0
go addAtomic(&y)
go subAtomic(&y)
wg.Wait()
fmt.Println("Atomic CAS with condition race: ", y)
elasped = time.Since(start)
fmt.Println(elasped)
start = time.Now()
wg.Add(1)
x = 0
go addMutex(&x)
wg.Wait()
fmt.Println("Mutex lock without condition race: ", x)
elasped = time.Since(start)
fmt.Println(elasped)
start = time.Now()
wg.Add(1)
y = 0
go addAtomic(&y)
wg.Wait()
fmt.Println("Atomic CAS without condition race: ", y)
elasped = time.Since(start)
fmt.Println(elasped)
}
网友评论